diff -u --recursive --new-file v2.1.86/linux/CREDITS linux/CREDITS --- v2.1.86/linux/CREDITS Thu Feb 12 20:56:03 1998 +++ linux/CREDITS Thu Feb 12 16:25:04 1998 @@ -33,6 +33,12 @@ S: B-2610 Wilrijk-Antwerpen S: Belgium +N: C. Scott Ananian +E: cananian@alumni.princeton.edu +W: http://www.pdos.lcs.mit.edu/~cananian +P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0 +D: pty improvements. + N: Erik Andersen E: andersee@debian.org W: http://www.inconnect.com/~andersen @@ -124,10 +130,12 @@ S: Germany N: Fred Baumgarten -E: dc6iq@insu1.etec.uni-karlsruhe.de +E: dc6iq@insl1.etec.uni-karlsruhe.de +E: dc6iq@adacom.org +E: dc6iq@db0ais.#hes.deu.eu (packet radio) D: NET-2 & netstat(8) -S: Kandelstrasse 27 -S: 76297 Stutensee +S: Soevener Strasse 11 +S: 53773 Hennef S: Germany N: Donald Becker @@ -674,6 +682,11 @@ S: Talstr. 1 S: D - 72072 Tuebingen S: Germany + +N: Jauder Ho +E: jauderho@transmeta.com +D: bug toaster (A1 sauce makes all the difference) +D: Transmeta BOFH in my free time N: Dirk Hohndel E: hohndel@aib.com diff -u --recursive --new-file v2.1.86/linux/Documentation/hayes-esp.txt linux/Documentation/hayes-esp.txt --- v2.1.86/linux/Documentation/hayes-esp.txt Mon Aug 11 16:57:59 1997 +++ linux/Documentation/hayes-esp.txt Thu Feb 12 15:47:44 1998 @@ -1,14 +1,37 @@ -HAYES ESP DRIVER VERSION 1.6 +HAYES ESP DRIVER VERSION 2.0 + +A big thanks to the people at Hayes, especially Alan Adamson. Their support +has enabled me to provide enhancements to the driver. + +Please report your experiences with this driver to me (arobinso@nyx.net). I +am looking for both positive and negative feedback. + +*** IMPORTANT CHANGES FOR 2.0 *** +Support for PIO mode. Five situations will cause PIO mode to be used: +1) A multiport card is detected. PIO mode will always be used. (8 port cards +do not support DMA). +2) The DMA channel is set to an invalid value (anything other than 1 or 3). +3) The DMA buffer/channel could not be allocated. The port will revert to PIO +mode until it is reopened. +4) Less than 33 bytes need to be transferred to/from the FIFOs. PIO mode will +be used for that transfer only. +5) A port needs to do a DMA transfer and another port is already using the +DMA channel. PIO mode will be used for that transfer only. + +A patch for setserial (2.12) is included to allow the ESP enhanced mode +configuration to be viewed and changed. +*** + +This package contains the files needed to compile a module to support the Hayes +ESP card. The drivers are basically a modified version of the serial drivers. Features: - Uses the enhanced mode of the ESP card, allowing a wider range of interrupts and features than compatibilty mode -- Uses DMA to transfer data to and from the ESP's FIFOs, reducing CPU load +- Uses DMA and 16 bit PIO mode to transfer data to and from the ESP's FIFOs, + reducing CPU load - Supports primary and secondary ports -- Special version of setserial can be used to view/change the enhanced mode - configuration. The setserial patch is distributed with the standalone - driver distribution. See http://www.nyx.net/~arobinso for more information. To compile/install: @@ -47,7 +70,8 @@ insmod esp divisor=0,0,0,0,0,0,0x84,0 The dma= option can be used to set the DMA channel. The channel can be either -1 or 3. For example, to set the dma channel to 3, the insmod command would be: +1 or 3. Specifying any other value will force the driver to use PIO mode. +For example, to set the dma channel to 3, the insmod command would be: insmod esp dma=3 diff -u --recursive --new-file v2.1.86/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.1.86/linux/Documentation/ioctl-number.txt Tue Dec 2 11:41:44 1997 +++ linux/Documentation/ioctl-number.txt Tue Feb 10 16:58:15 1998 @@ -1,5 +1,5 @@ Ioctl Numbers -1 Sep 1997 +28 Jan 1998 Michael Chastain @@ -86,7 +86,7 @@ 'W' 28-2F linux/iso16-relay.h in development 'Y' all linux/cyclades.h 'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html -'b' 00-3F bit3 vme host bridge in development: +'b' 00-FF bit3 vme host bridge in development: 'c' all linux/comstats.h 'f' all linux/ext2_fs.h @@ -108,6 +108,8 @@ 'w' all CERN SCI driver in development 'z' 00-3F CAN bus card in development: +'z' 40-7F CAN bas card in development: + 0x89 00-0F asm-i386/sockios.h 0x89 10-DF linux/sockios.h 0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range diff -u --recursive --new-file v2.1.86/linux/Documentation/m68k/framebuffer.txt linux/Documentation/m68k/framebuffer.txt --- v2.1.86/linux/Documentation/m68k/framebuffer.txt Tue May 13 22:41:00 1997 +++ linux/Documentation/m68k/framebuffer.txt Thu Feb 12 16:30:11 1998 @@ -3,7 +3,7 @@ ---------------------------------- Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) -Last revised: March 23, 1997 +Last revised: January 24, 1998 0. Introduction @@ -23,85 +23,47 @@ -------------------------- From the user's point of view, the frame buffer device looks just like any -other device in /dev. It's a character device using major 29, the minor is -divided into a frame buffer number in the upper 3 bits (allowing max. 8 frame -buffers simultaneously) and a resolution code in the lower 5 bits of the minor. +other device in /dev. It's a character device using major 29; the minor +specifies the frame buffer number. By convention, the following device nodes are used (numbers indicate the device minor numbers): - First frame buffer - 0 = /dev/fb0current Current resolution - 1 = /dev/fb0autodetect Default resolution - 2 = /dev/fb0predefined0 Predefined resolutions (22) - ... - 23 = /dev/fb0predefined21 - 24 = /dev/fb0user0 User defined resolutions (8) - ... - 31 = /dev/fb0user7 - - Second frame buffer - 32 = /dev/fb1current Current resolution - 33 = /dev/fb1autodetect Default resolution - 34 = /dev/fb1predefined0 Predefined resolutions (22) - ... - 55 = /dev/fb1predefined21 - 56 = /dev/fb1user0 User defined resolutions (8) - ... - 63 = /dev/fb1user7 + 0 = /dev/fb0 First frame buffer + 32 = /dev/fb1 Second frame buffer + ... + 224 = /dev/fb7 8th frame buffer -and so on... +For backwards compatibility, you may want to create the following symbolic +links: + + /dev/fb0current -> fb0 + /dev/fb1current -> fb1 -The device with (minor & 31) == 0 (/dev/fb?current) stands for the frame buffer -together with the currently set video parameters; (minor & 31) == 1 -(/dev/fb?autodetect) is the video mode detected at boot time. Any other minor -stands for some predefined or user defined video mode. - -The predefined entries (/dev/fb?predefined*) usually have a device dependent -name, e.g. for major 29, minor 5, we have /dev/fb0multiscan on Amiga and -/dev/fb0ttmid on Atari. These are meant to contain hardware dependent -resolutions. - -The user defined resolutions (/dev/fb?user?) are meant to be filled in by the -user. This way the user can store his favorite 8 resolutions during boot up. - -Note: if you need more than 8 user defined resolutions, you can always override -the predefined resolutions by storing them in one of the predefined entries. -But this is not recommended. Similarly, if there are more than 22 predefined -resolutions, the device writer can decide to store them in the user defined -entries. - -If the device is opened (for writing), the frame buffer driver switches to the -selected video mode. Thus, you can switch video modes by writing to a frame -buffer device, e.g. - - > /dev/fb0ttlow - -will switch your video to TT low mode. Note: if you specify a resolution which -contains a value that's not possible on your hardware, the frame buffer device -will round it up (if possible) or return an error condition. +and so on... The frame buffer devices are also `normal' memory devices, this means, you can read and write their contents. You can, for example, make a screen snapshot by - cp /dev/fb0current myfile + cp /dev/fb0 myfile There also can be more than one frame buffer at a time, e.g. if you have a graphics card in addition to the built-in hardware. The corresponding frame -buffer devices (/dev/fb0* and /dev/fb1* etc.) work independently. +buffer devices (/dev/fb0 and /dev/fb1 etc.) work independently. Application software that uses the frame buffer device (e.g. the X server) will -use /dev/fb0current by default. You can specify an alternative resolution by -setting the environment variable $FRAMEBUFFER to the path name of a frame -buffer device, e.g. (for sh/bash users): +use /dev/fb0 by default (older software uses /dev/fb0current). You can specify +an alternative frame buffer device by setting the environment variable +$FRAMEBUFFER to the path name of a frame buffer device, e.g. (for sh/bash +users): - export FRAMEBUFFER=/dev/fb0multiscan + export FRAMEBUFFER=/dev/fb1 or (for csh users): - setenv FRAMEBUFFER /dev/fb0multiscan + setenv FRAMEBUFFER /dev/fb1 -After this the X server will use the multiscan video mode. +After this the X server will use the second frame buffer. 2. Programmer's View of /dev/fb* @@ -152,23 +114,20 @@ -------------------------------------- Frame buffer resolutions are maintained using the utility `fbset'. It allows to -change the video mode properties of the current or a user defined resolution. -It's main usage is to tune video modes and to store custom resolutions into one -of the /dev/fb?user? entries, e.g. during boot up in one of your /etc/rc.* or -/etc/init.d/* files, after which those resolutions can be used by applications. +change the video mode properties of the current resolution. It's main usage is +to change the current video mode, e.g. during boot up in one of your /etc/rc.* +or /etc/init.d/* files. Fbset uses a video mode database stored in a configuration file, so you can -easily add your own modes and refer to them with a simple identifier. The fbset -install script also creates the special device nodes for the device dependent -predefined resolutions. +easily add your own modes and refer to them with a simple identifier. 4. The X Server --------------- The X server (XF68_FBDev) is the most notable application program for the frame -buffer device. The current X server is part of the XFree86/XFree68 release 3.2 -package and has 2 modes: +buffer device. The current X server is part of the XFree86/XFree68 release +3.3.1 package and has 2 modes: - If the `Display' subsection for the `fbdev' driver in the /etc/XF86Config file contains a @@ -347,7 +306,7 @@ - The mighty kernel sources: o linux/include/linux/fb.h o linux/drivers/char/fbmem.c - o linux/arch/m68k/*/*fb.c + o linux/drivers/video/*fb.c 8. Downloading diff -u --recursive --new-file v2.1.86/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt --- v2.1.86/linux/Documentation/m68k/kernel-options.txt Sat Nov 29 10:33:18 1997 +++ linux/Documentation/m68k/kernel-options.txt Thu Feb 12 16:30:11 1998 @@ -3,8 +3,8 @@ Command Line Options for Linux/m68k =================================== -Date: Oct 6, 1997 -Linux/m68k version: 2.0.21 +Last Update: Nov 28, 1997 +Linux/m68k version: 2.1.64 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek) Update: jds@kom.auc.dk (Jes Sorensen) @@ -191,6 +191,7 @@ - "ser2": SCC channel B serial port ("Modem2"); parameters: 9600bps, 8N1 - "ser" : default serial port This is "ser2" for a Falcon, and "ser1" for any other machine + - "midi": The MIDI port; parameters: 31250bps, 8N1 - "par" : parallel port The printing routine for this implements a timeout for the case there's no printer connected (else the kernel would @@ -408,19 +409,7 @@ Often, extended interval video hardware has to be activated somehow. For this, see the "sw_*" options below. -4.1.6) sw_acia, sw_snd6, sw_snd7 --------------------------------- - -This specifies the method for turning on extended internal video -hardware, like OverScan. Several methods are in use: - - sw_acia: Set RTS of the keyboard ACIA high - sw_snd6: Set bit 6 of the PSG port A - sw_snd7: Set bit 7 of the PSG port A - -These sub-options are generally only useful together with "internal:". - -4.1.7) external: +4.1.6) external: ---------------- Syntax: @@ -509,13 +498,13 @@ therefore we don't support hardware-dependend functions like hardware-scroll, panning or blanking. -4.1.8) eclock: +4.1.7) eclock: -------------- The external pixel clock attached to the Falcon VIDEL shifter. This currently works only with the ScreenWonder! -4.1.9) monitorcap: +4.1.8) monitorcap: ------------------- Syntax: monitorcap:;;; @@ -532,7 +521,7 @@ The defaults for TV/SC1224/SC1435 cover both PAL and NTSC standards. -4.1.10) keep +4.1.9) keep ------------ If this option is given, the framebuffer device doesn't do any video @@ -650,7 +639,62 @@ can be performed in optimal order. Not all SCSI devices support tagged queuing (:-(). +4.6 switches= +------------- + +Syntax: switches= + + With this option you can switch some hardware lines that are often +used to enable/disable certain hardware extensions. Examples are +OverScan, overclocking, ... + + The is a comma-separated list of the following +items: + + ikbd: set RTS of the keyboard ACIA high + midi: set RTS of the MIDI ACIA high + snd6: set bit 6 of the PSG port A + snd7: set bit 6 of the PSG port A + +It doesn't make sense to mention a switch more than once (no +difference to only once), but you can give as many switches as you +want to enable different features. The switch lines are set as early +as possible during kernel initialization (even before determining the +present hardware.) + + All of the items can also be prefixed with "ov_", i.e. "ov_ikbd", +"ov_midi", ... These options are meant for switching on an OverScan +video extension. The difference to the bare option is that the +switch-on is done after video initialization, and somehow synchronized +to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched +off before rebooting, so that OverScan is disabled and TOS boots +correctly. + + If you give an option both, with and without the "ov_" prefix, the +earlier initialization ("ov_"-less) takes precedence. But the +switching-off on reset still happens in this case. + +4.5) stram_swap= +---------------- + +Syntax: stram_swap=[,] + This option is available only if the kernel has been compiled with +CONFIG_STRAM_SWAP enabled. Normally, the kernel then determines +dynamically whether to actually use ST-RAM as swap space. (Currently, +the fraction of ST-RAM must be less or equal 1/3 of total memory to +enable this swapping.) You can override the kernel's decision by +specifying this option. 1 for means always enable the swap, +even if you have less alternate RAM. 0 stands for never swap to +ST-RAM, even if it's small enough compared to the rest of memory. + + If ST-RAM swapping is enabled, the kernel usually uses all free +ST-RAM as swap "device". (If the kernel resides in ST-RAM, the region +allocated by it is obviously never used for swapping :-) You can also +limit this amount by specifying the second parameter, , if +you want to use parts of ST-RAM as normal system memory. is +in kBytes and the number should be a multiple of 4 (otherwise: rounded +down). 5) Options for Amiga Only: ========================== diff -u --recursive --new-file v2.1.86/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.86/linux/MAINTAINERS Wed Feb 4 11:35:59 1998 +++ linux/MAINTAINERS Thu Feb 12 16:20:10 1998 @@ -348,8 +348,8 @@ S: Maintained MENUCONFIG: -P: William Roadcap -M: roadcapw@cfw.com +P: Michael Elizabeth Chastain +M: mec@shout.net L: linux-kernel@vger.rutgers.edu S: Maintained diff -u --recursive --new-file v2.1.86/linux/Makefile linux/Makefile --- v2.1.86/linux/Makefile Thu Feb 12 20:56:03 1998 +++ linux/Makefile Thu Feb 12 20:56:41 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 86 +SUBLEVEL = 87 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.86/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.1.86/linux/arch/alpha/Makefile Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/Makefile Thu Feb 12 13:31:28 1998 @@ -18,8 +18,12 @@ SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib \ arch/alpha/math-emu CORE_FILES := arch/alpha/kernel/kernel.o arch/alpha/mm/mm.o $(CORE_FILES) -LIBS := $(TOPDIR)/arch/alpha/math-emu/math-emu.a \ - $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a + +ifeq ($(CONFIG_MATHEMU),y) + CORE_FILES := $(CORE_FILES) arch/alpha/math-emu/math-emu.o +endif + +LIBS := arch/alpha/lib/lib.a $(LIBS) arch/alpha/lib/lib.a MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot diff -u --recursive --new-file v2.1.86/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.86/linux/arch/alpha/config.in Thu Feb 12 20:56:03 1998 +++ linux/arch/alpha/config.in Thu Feb 12 13:31:28 1998 @@ -245,6 +245,12 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel FP software completion' CONFIG_MATHEMU +else + define_bool CONFIG_MATHEMU y +fi + bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --recursive --new-file v2.1.86/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.1.86/linux/arch/alpha/defconfig Fri Jan 30 11:28:05 1998 +++ linux/arch/alpha/defconfig Thu Feb 12 13:31:28 1998 @@ -30,14 +30,19 @@ # CONFIG_ALPHA_JENSEN is not set # CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_MIKASA is not set +# CONFIG_ALPHA_NORITAKE is not set CONFIG_ALPHA_ALCOR=y +# CONFIG_ALPHA_MIATA is not set +# CONFIG_ALPHA_SABLE is not set +# CONFIG_ALPHA_BOOK1 is not set # CONFIG_ALPHA_P2K is not set CONFIG_PCI=y -CONFIG_PCI_OLD_PROC=y CONFIG_ALPHA_EV5=y CONFIG_ALPHA_CIA=y CONFIG_ALPHA_SRM=y +CONFIG_ALPHA_EISA=y CONFIG_TGA_CONSOLE=y +CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_SYSCTL=y @@ -70,28 +75,35 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_EZ is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set # CONFIG_BLK_DEV_HD is not set # # Networking options # +# CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set # CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set # # (it is safe to leave these untouched) # -# CONFIG_INET_PCTCP is not set # CONFIG_INET_RARP is not set -CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y @@ -100,7 +112,6 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set -# CONFIG_AX25 is not set # # SCSI support @@ -121,6 +132,7 @@ # # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers @@ -139,11 +151,15 @@ # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_SEAGATE is not set @@ -177,13 +193,19 @@ # CONFIG_FDDI is not set # CONFIG_DLCI is not set # CONFIG_PPP is not set -# CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set # CONFIG_TR is not set +# CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -192,6 +214,7 @@ # CD-ROM drivers (not for SCSI or IDE/ATAPI drives) # # CONFIG_CD_NO_IDESCSI is not set +CONFIG_CDROM=y # # Filesystems @@ -199,25 +222,29 @@ # CONFIG_QUOTA is not set # CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set # CONFIG_SMB_FS is not set -CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set # CONFIG_ROMFS_FS is not set # CONFIG_AUTOFS_FS is not set # CONFIG_UFS_FS is not set # CONFIG_MAC_PARTITION is not set +# CONFIG_NLS is not set # # Character devices @@ -225,6 +252,7 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_MOUSE=y @@ -236,12 +264,18 @@ # CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_FTAPE is not set # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set +# CONFIG_MISC_RADIO is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set # # Sound @@ -252,4 +286,5 @@ # Kernel hacking # # CONFIG_PROFILE is not set +CONFIG_MATHEMU=y # CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.1.86/linux/arch/alpha/kernel/Makefile Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/Makefile Thu Feb 12 13:31:28 1998 @@ -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 \ - bios32.o ptrace.o time.o + bios32.o ptrace.o time.o fpreg.o OX_OBJS := alpha_ksyms.o diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.1.86/linux/arch/alpha/kernel/alpha_ksyms.c Thu Feb 12 20:56:04 1998 +++ linux/arch/alpha/kernel/alpha_ksyms.c Thu Feb 12 13:31:28 1998 @@ -21,6 +21,7 @@ #include #include #include +#include #define __KERNEL_SYSCALLS__ #include @@ -88,6 +89,8 @@ EXPORT_SYMBOL(hwrpb); EXPORT_SYMBOL(wrusp); EXPORT_SYMBOL(start_thread); +EXPORT_SYMBOL(alpha_read_fp_reg); +EXPORT_SYMBOL(alpha_write_fp_reg); /* In-kernel system calls. */ EXPORT_SYMBOL(__kernel_thread); @@ -109,6 +112,11 @@ EXPORT_SYMBOL(csum_partial_copy); EXPORT_SYMBOL(csum_partial_copy_from_user); EXPORT_SYMBOL(csum_ipv6_magic); + +#ifdef CONFIG_MATHEMU_MODULE +extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +EXPORT_SYMBOL(alpha_fp_emul_imprecise); +#endif /* * The following are specially called from the uaccess assembly stubs. diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.86/linux/arch/alpha/kernel/entry.S Thu Feb 12 20:56:04 1998 +++ linux/arch/alpha/kernel/entry.S Thu Feb 12 16:44:15 1998 @@ -1046,7 +1046,7 @@ .quad sys_bdflush /* 300 */ .quad sys_sethae .quad sys_mount - .quad sys_adjtimex + .quad sys_old_adjtimex .quad sys_swapoff .quad sys_getdents /* 305 */ .quad alpha_create_module diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/fpreg.c linux/arch/alpha/kernel/fpreg.c --- v2.1.86/linux/arch/alpha/kernel/fpreg.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/fpreg.c Thu Feb 12 13:31:28 1998 @@ -0,0 +1,104 @@ +/* + * kernel/fpreg.c + * + * (C) Copyright 1998 Linus Torvalds + */ + +unsigned long +alpha_read_fp_reg (unsigned long reg) +{ + unsigned long r; + + switch (reg) { + case 0: asm ("stt $f0,%0" : "m="(r)); break; + case 1: asm ("stt $f1,%0" : "m="(r)); break; + case 2: asm ("stt $f2,%0" : "m="(r)); break; + case 3: asm ("stt $f3,%0" : "m="(r)); break; + case 4: asm ("stt $f4,%0" : "m="(r)); break; + case 5: asm ("stt $f5,%0" : "m="(r)); break; + case 6: asm ("stt $f6,%0" : "m="(r)); break; + case 7: asm ("stt $f7,%0" : "m="(r)); break; + case 8: asm ("stt $f8,%0" : "m="(r)); break; + case 9: asm ("stt $f9,%0" : "m="(r)); break; + case 10: asm ("stt $f10,%0" : "m="(r)); break; + case 11: asm ("stt $f11,%0" : "m="(r)); break; + case 12: asm ("stt $f12,%0" : "m="(r)); break; + case 13: asm ("stt $f13,%0" : "m="(r)); break; + case 14: asm ("stt $f14,%0" : "m="(r)); break; + case 15: asm ("stt $f15,%0" : "m="(r)); break; + case 16: asm ("stt $f16,%0" : "m="(r)); break; + case 17: asm ("stt $f17,%0" : "m="(r)); break; + case 18: asm ("stt $f18,%0" : "m="(r)); break; + case 19: asm ("stt $f19,%0" : "m="(r)); break; + case 20: asm ("stt $f20,%0" : "m="(r)); break; + case 21: asm ("stt $f21,%0" : "m="(r)); break; + case 22: asm ("stt $f22,%0" : "m="(r)); break; + case 23: asm ("stt $f23,%0" : "m="(r)); break; + case 24: asm ("stt $f24,%0" : "m="(r)); break; + case 25: asm ("stt $f25,%0" : "m="(r)); break; + case 26: asm ("stt $f26,%0" : "m="(r)); break; + case 27: asm ("stt $f27,%0" : "m="(r)); break; + case 28: asm ("stt $f28,%0" : "m="(r)); break; + case 29: asm ("stt $f29,%0" : "m="(r)); break; + case 30: asm ("stt $f30,%0" : "m="(r)); break; + case 31: asm ("stt $f31,%0" : "m="(r)); break; + default: + break; + } + return r; +} + +#if 1 +/* + * This is IMHO the better way of implementing LDT(). But it + * has the disadvantage that gcc 2.7.0 refuses to compile it + * (invalid operand constraints), so instead, we use the uglier + * macro below. + */ +# define LDT(reg,val) \ + asm volatile ("ldt $f"#reg",%0" : : "m"(val)); +#else +# define LDT(reg,val) \ + asm volatile ("ldt $f"#reg",0(%0)" : : "r"(&val)); +#endif + +void +alpha_write_fp_reg (unsigned long reg, unsigned long val) +{ + switch (reg) { + case 0: LDT( 0, val); break; + case 1: LDT( 1, val); break; + case 2: LDT( 2, val); break; + case 3: LDT( 3, val); break; + case 4: LDT( 4, val); break; + case 5: LDT( 5, val); break; + case 6: LDT( 6, val); break; + case 7: LDT( 7, val); break; + case 8: LDT( 8, val); break; + case 9: LDT( 9, val); break; + case 10: LDT(10, val); break; + case 11: LDT(11, val); break; + case 12: LDT(12, val); break; + case 13: LDT(13, val); break; + case 14: LDT(14, val); break; + case 15: LDT(15, val); break; + case 16: LDT(16, val); break; + case 17: LDT(17, val); break; + case 18: LDT(18, val); break; + case 19: LDT(19, val); break; + case 20: LDT(20, val); break; + case 21: LDT(21, val); break; + case 22: LDT(22, val); break; + case 23: LDT(23, val); break; + case 24: LDT(24, val); break; + case 25: LDT(25, val); break; + case 26: LDT(26, val); break; + case 27: LDT(27, val); break; + case 28: LDT(28, val); break; + case 29: LDT(29, val); break; + case 30: LDT(30, val); break; + case 31: LDT(31, val); break; + default: + break; + } +} diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.1.86/linux/arch/alpha/kernel/head.S Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/head.S Thu Feb 12 13:31:28 1998 @@ -121,37 +121,3 @@ call_pal PAL_cserve ret ($26) .end cserve_dis - - # - # The following two functions don't need trapb/excb instructions - # around the mf_fpcr/mt_fpcr instructions because (a) the kernel - # never generates arithmetic faults and (b) call_pal instructions - # are implied trap barriers. - # - .align 3 - .globl rdfpcr - .ent rdfpcr -rdfpcr: - lda $30,-0x10($30) - stt $f0,0($30) - mf_fpcr $f0 - stt $f0,8($30) - ldt $f0,0($30) - ldq $0,8($30) - lda $30,0x10($30) - ret ($26) - .end rdfpcr - - .align 3 - .globl wrfpcr - .ent wrfpcr -wrfpcr: - lda $30,-0x10($30) - stt $f0,0($30) - stq $16,8($30) - ldt $f0,8($30) - mt_fpcr $f0 - ldt $f0,0($30) - lda $30,0x10($30) - ret ($26) - .end wrfpcr diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.1.86/linux/arch/alpha/kernel/osf_sys.c Fri Jan 30 11:28:05 1998 +++ linux/arch/alpha/kernel/osf_sys.c Thu Feb 12 16:44:15 1998 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -925,6 +926,7 @@ extern int do_setitimer(int which, struct itimerval *, struct itimerval *); asmlinkage int sys_utimes(char *, struct timeval *); extern int sys_wait4(pid_t, int *, int, struct rusage *); +extern int do_adjtimex(struct timex *); struct timeval32 { @@ -1269,4 +1271,58 @@ return 0; fault: return -EFAULT; +} + + +struct timex32 { + unsigned int modes; /* mode selector */ + long offset; /* time offset (usec) */ + long freq; /* frequency offset (scaled ppm) */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ + int status; /* clock command/status */ + long constant; /* pll time constant */ + long precision; /* clock precision (usec) (read only) */ + long tolerance; /* clock frequency tolerance (ppm) + * (read only) + */ + struct timeval32 time; /* (read only) */ + long tick; /* (modified) usecs between clock ticks */ + + long ppsfreq; /* pps frequency (scaled ppm) (ro) */ + long jitter; /* pps jitter (us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long stabil; /* pps stability (scaled ppm) (ro) */ + long jitcnt; /* jitter limit exceeded (ro) */ + long calcnt; /* calibration intervals (ro) */ + long errcnt; /* calibration errors (ro) */ + long stbcnt; /* stability limit exceeded (ro) */ + + int :32; int :32; int :32; int :32; + int :32; int :32; int :32; int :32; + int :32; int :32; int :32; int :32; +}; + +asmlinkage int sys_old_adjtimex(struct timex32 *txc_p) +{ + struct timex txc; + int ret; + + /* copy relevant bits of struct timex. */ + if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) || + copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - + offsetof(struct timex32, time))) + return -EFAULT; + + if ((ret = do_adjtimex(&txc))) + return ret; + + /* copy back to timex32 */ + if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) || + (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - + offsetof(struct timex32, tick))) || + (put_tv32(&txc_p->time, &txc.time))) + return -EFAULT; + + return 0; } diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.1.86/linux/arch/alpha/kernel/traps.c Thu Feb 12 20:56:04 1998 +++ linux/arch/alpha/kernel/traps.c Thu Feb 12 13:31:28 1998 @@ -105,14 +105,24 @@ do_exit(SIGSEGV); } +#ifndef CONFIG_MATHEMU +static long dummy_alpha_fp_emul_imprecise(struct pt_regs *r, unsigned long wm) +{ + return 0; +} + +long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask) + = dummy_alpha_fp_emul_imprecise; +#else +long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask); +#endif + asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { if ((summary & 1)) { - extern long alpha_fp_emul_imprecise (struct pt_regs * regs, - unsigned long write_mask); /* * Software-completion summary bit is set, so try to * emulate the instruction. diff -u --recursive --new-file v2.1.86/linux/arch/alpha/math-emu/Makefile linux/arch/alpha/math-emu/Makefile --- v2.1.86/linux/arch/alpha/math-emu/Makefile Thu Dec 21 22:22:05 1995 +++ linux/arch/alpha/math-emu/Makefile Thu Feb 12 13:31:28 1998 @@ -2,11 +2,11 @@ # Makefile for math-emulator files... # -OBJS = fp-emul.o ieee-math.o +O_TARGET := math-emu.o +O_OBJS := fp-emul.o ieee-math.o -math-emu.a: $(OBJS) - $(AR) rcs $@ $(OBJS) - -dep: +ifeq ($(CONFIG_MATHEMU),m) +M_OBJS := $(O_TARGET) +endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c --- v2.1.86/linux/arch/alpha/math-emu/fp-emul.c Mon Jun 16 16:35:53 1997 +++ linux/arch/alpha/math-emu/fp-emul.c Thu Feb 12 13:31:28 1998 @@ -1,5 +1,5 @@ +#include #include - #include #include @@ -52,111 +52,33 @@ #define MISC_TRAPB 0x0000 #define MISC_EXCB 0x0400 - -extern unsigned long rdfpcr (void); -extern void wrfpcr (unsigned long); +extern unsigned long alpha_read_fp_reg (unsigned long reg); +extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); -unsigned long -alpha_read_fp_reg (unsigned long reg) -{ - unsigned long r; +#ifdef MODULE - switch (reg) { - case 0: asm ("stt $f0,%0" : "m="(r)); break; - case 1: asm ("stt $f1,%0" : "m="(r)); break; - case 2: asm ("stt $f2,%0" : "m="(r)); break; - case 3: asm ("stt $f3,%0" : "m="(r)); break; - case 4: asm ("stt $f4,%0" : "m="(r)); break; - case 5: asm ("stt $f5,%0" : "m="(r)); break; - case 6: asm ("stt $f6,%0" : "m="(r)); break; - case 7: asm ("stt $f7,%0" : "m="(r)); break; - case 8: asm ("stt $f8,%0" : "m="(r)); break; - case 9: asm ("stt $f9,%0" : "m="(r)); break; - case 10: asm ("stt $f10,%0" : "m="(r)); break; - case 11: asm ("stt $f11,%0" : "m="(r)); break; - case 12: asm ("stt $f12,%0" : "m="(r)); break; - case 13: asm ("stt $f13,%0" : "m="(r)); break; - case 14: asm ("stt $f14,%0" : "m="(r)); break; - case 15: asm ("stt $f15,%0" : "m="(r)); break; - case 16: asm ("stt $f16,%0" : "m="(r)); break; - case 17: asm ("stt $f17,%0" : "m="(r)); break; - case 18: asm ("stt $f18,%0" : "m="(r)); break; - case 19: asm ("stt $f19,%0" : "m="(r)); break; - case 20: asm ("stt $f20,%0" : "m="(r)); break; - case 21: asm ("stt $f21,%0" : "m="(r)); break; - case 22: asm ("stt $f22,%0" : "m="(r)); break; - case 23: asm ("stt $f23,%0" : "m="(r)); break; - case 24: asm ("stt $f24,%0" : "m="(r)); break; - case 25: asm ("stt $f25,%0" : "m="(r)); break; - case 26: asm ("stt $f26,%0" : "m="(r)); break; - case 27: asm ("stt $f27,%0" : "m="(r)); break; - case 28: asm ("stt $f28,%0" : "m="(r)); break; - case 29: asm ("stt $f29,%0" : "m="(r)); break; - case 30: asm ("stt $f30,%0" : "m="(r)); break; - case 31: asm ("stt $f31,%0" : "m="(r)); break; - default: - break; - } - return r; -} +MODULE_DESCRIPTION("FP Software completion module"); +extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +static long (*save_emul)(struct pt_regs *, unsigned long); +long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long); -#if 0 -/* - * This is IMHO the better way of implementing LDT(). But it - * has the disadvantage that gcc 2.7.0 refuses to compile it - * (invalid operand constraints), so instead, we use the uglier - * macro below. - */ -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",%0" :: "m"(val)); -#else -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",0(%0)" :: "r"(&val)); -#endif +int init_module(void) +{ + save_emul = alpha_fp_emul_imprecise; + alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise; + return 0; +} -void -alpha_write_fp_reg (unsigned long reg, unsigned long val) +void cleanup_module(void) { - switch (reg) { - case 0: LDT( 0, val); break; - case 1: LDT( 1, val); break; - case 2: LDT( 2, val); break; - case 3: LDT( 3, val); break; - case 4: LDT( 4, val); break; - case 5: LDT( 5, val); break; - case 6: LDT( 6, val); break; - case 7: LDT( 7, val); break; - case 8: LDT( 8, val); break; - case 9: LDT( 9, val); break; - case 10: LDT(10, val); break; - case 11: LDT(11, val); break; - case 12: LDT(12, val); break; - case 13: LDT(13, val); break; - case 14: LDT(14, val); break; - case 15: LDT(15, val); break; - case 16: LDT(16, val); break; - case 17: LDT(17, val); break; - case 18: LDT(18, val); break; - case 19: LDT(19, val); break; - case 20: LDT(20, val); break; - case 21: LDT(21, val); break; - case 22: LDT(22, val); break; - case 23: LDT(23, val); break; - case 24: LDT(24, val); break; - case 25: LDT(25, val); break; - case 26: LDT(26, val); break; - case 27: LDT(27, val); break; - case 28: LDT(28, val); break; - case 29: LDT(29, val); break; - case 30: LDT(30, val); break; - case 31: LDT(31, val); break; - default: - break; - } + alpha_fp_emul_imprecise = save_emul; } +#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise + +#endif /* MODULE */ /* * Emulate the floating point instruction at address PC. Returns 0 if @@ -334,6 +256,8 @@ unsigned long trigger_pc = regs->pc - 4; unsigned long insn, opcode, rc; + MOD_INC_USE_COUNT; + /* * Turn off the bits corresponding to registers that are the * target of instructions that set bits in the exception @@ -354,12 +278,14 @@ case OPC_PAL: case OPC_JSR: case 0x30 ... 0x3f: /* branches */ + MOD_DEC_USE_COUNT; return 0; case OPC_MISC: switch (insn & 0xffff) { case MISC_TRAPB: case MISC_EXCB: + MOD_DEC_USE_COUNT; return 0; default: @@ -386,11 +312,13 @@ { /* re-execute insns in trap-shadow: */ regs->pc = trigger_pc + 4; + MOD_DEC_USE_COUNT; return 1; } break; } trigger_pc -= 4; } + MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.1.86/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c --- v2.1.86/linux/arch/alpha/math-emu/ieee-math.c Thu Apr 11 23:49:30 1996 +++ linux/arch/alpha/math-emu/ieee-math.c Thu Feb 12 13:31:28 1998 @@ -137,9 +137,8 @@ static inline void mul64 (const unsigned long a, const unsigned long b, unsigned long c[2]) { - asm ("mulq %2,%3,%0\n\t" - "umulh %2,%3,%1" - : "r="(c[0]), "r="(c[1]) : "r"(a), "r"(b)); + c[0] = a * b; + asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b)); } @@ -276,7 +275,7 @@ { unsigned long res, sticky; - if (!a->f[0] && !a->f[1]) { + if (!a->e && !a->f[0] && !a->f[1]) { *b = (unsigned long) a->s << 63; /* return +/-0 */ return 0; } @@ -356,7 +355,7 @@ { unsigned long res, sticky; - if (!a->f[0] && !a->f[1]) { + if (!a->e && !a->f[0] && !a->f[1]) { *b = (unsigned long) a->s << 63; /* return +/-0 */ return 0; } @@ -384,7 +383,7 @@ a->e = -0x3ff; } } - if (a->e > 0x3ff) { + if (a->e >= 0x3ff) { res = FPCR_OVF | FPCR_INE; if (f & IEEE_TRAP_ENABLE_OVF) { a->e -= 0x600; /* scale down result by 2^alpha */ @@ -1143,12 +1142,9 @@ return 0; } op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e; + op_c.e = op_a.e + op_b.e - 55; mul64(op_a.f[0], op_b.f[0], op_c.f); - normalize(&op_c); - op_c.e -= 55; /* drop the 55 original bits. */ - return round_s_ieee(f, &op_c, c); } @@ -1200,11 +1196,8 @@ return 0; } op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e; + op_c.e = op_a.e + op_b.e - 55; mul64(op_a.f[0], op_b.f[0], op_c.f); - - normalize(&op_c); - op_c.e -= 55; /* drop the 55 original bits. */ return round_t_ieee(f, &op_c, c); } diff -u --recursive --new-file v2.1.86/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.86/linux/arch/i386/kernel/irq.c Thu Feb 12 20:56:04 1998 +++ linux/arch/i386/kernel/irq.c Wed Feb 11 15:17:41 1998 @@ -570,22 +570,31 @@ unsigned long __global_save_flags(void) { - return global_irq_holder == (unsigned char) smp_processor_id(); + if (!local_irq_count[smp_processor_id()]) + return global_irq_holder == (unsigned char) smp_processor_id(); + else { + unsigned long x; + __save_flags(x); + return x; + } } void __global_restore_flags(unsigned long flags) { - switch (flags) { - case 0: - __global_sti(); - break; - case 1: - __global_cli(); - break; - default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); - } + if (!local_irq_count[smp_processor_id()]) { + switch (flags) { + case 0: + __global_sti(); + break; + case 1: + __global_cli(); + break; + default: + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); + } + } else + __restore_flags(flags); } #endif diff -u --recursive --new-file v2.1.86/linux/arch/m68k/Makefile linux/arch/m68k/Makefile --- v2.1.86/linux/arch/m68k/Makefile Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/Makefile Thu Feb 12 16:30:11 1998 @@ -26,6 +26,7 @@ LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds +# without -fno-strength-reduce the 53c7xx.c driver fails ;-( CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 ifdef CONFIG_OPTIMIZE_040 @@ -33,7 +34,7 @@ endif ifdef CONFIG_OPTIMIZE_060 -CFLAGS := $(CFLAGS) -m68020-40 +CFLAGS := $(CFLAGS) -m68060 endif ifdef CONFIG_KGDB @@ -63,10 +64,14 @@ SUBDIRS := $(SUBDIRS) arch/m68k/mac endif -ifdef CONFIG_VT -# add in console.a after {amiga,atari}.o that need it -CORE_FILES := $(CORE_FILES) arch/m68k/console/console.a -SUBDIRS := $(SUBDIRS) arch/m68k/console +ifdef CONFIG_APOLLO +CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o +SUBDIRS := $(SUBDIRS) arch/m68k/apollo +endif + +ifdef CONFIG_MVME16x +CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o +SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x endif ifdef CONFIG_M68040 @@ -98,9 +103,6 @@ else gzip -9c vmlinux >vmlinux.gz endif - -bootstrap: dummy - @$(MAKEBOOT) bootstrap archclean: rm -f vmlinux.gz diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile --- v2.1.86/linux/arch/m68k/amiga/Makefile Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/Makefile Thu Feb 12 16:30:12 1998 @@ -8,16 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := amiga.o -O_OBJS := config.o amikeyb.o amiints.o cia.o \ - chipram.o amisound.o amifb.o zorro.o +O_OBJS := config.o amiints.o cia.o chipram.o amisound.o zorro.o OX_OBJS := amiga_ksyms.o - -ifdef CONFIG_FB_CYBER -O_OBJS := $(O_OBJS) cyberfb.o -endif - -ifdef CONFIG_FB_RETINAZ3 -O_OBJS := $(O_OBJS) retz3fb.o -endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v2.1.86/linux/arch/m68k/amiga/amiints.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/amiints.c Thu Feb 12 16:30:12 1998 @@ -331,7 +331,7 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp) { - kstat.interrupts[SYS_IRQS + irq]++; + kstat.irqs[0][SYS_IRQS + irq]++; ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); } @@ -340,7 +340,7 @@ irq_node_t *node, *slow_nodes; unsigned short flags; - kstat.interrupts[SYS_IRQS + irq]++; + kstat.irqs[0][SYS_IRQS + irq]++; if (server->count++) server->reentrance = 1; /* serve first fast and normal handlers */ @@ -489,7 +489,7 @@ if (node->flags & IRQ_FLG_STD) continue; len += sprintf(buf+len, "ami %2d: %10u ", i, - kstat.interrupts[SYS_IRQS + i]); + kstat.irqs[0][SYS_IRQS + i]); do { if (ami_servers[i]) { if (node->flags & IRQ_FLG_FAST) diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/cia.c linux/arch/m68k/amiga/cia.c --- v2.1.86/linux/arch/m68k/amiga/cia.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/cia.c Thu Feb 12 16:30:12 1998 @@ -145,7 +145,7 @@ custom.intreq = base->int_mask; for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) { if (ints & 1) { - kstat.interrupts[irq]++; + kstat.irqs[0][irq]++; base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp); } ints >>= 1; @@ -181,7 +181,7 @@ for (i = 0; i < CIA_IRQS; i++) { if (!(base->irq_list[i].flags & IRQ_FLG_STD)) { len += sprintf(buf+len, "cia %2d: %10d ", j + i, - kstat.interrupts[SYS_IRQS + j + i]); + kstat.irqs[0][SYS_IRQS + j + i]); if (base->irq_list[i].flags & IRQ_FLG_LOCK) len += sprintf(buf+len, "L "); else diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v2.1.86/linux/arch/m68k/amiga/config.c Mon Jul 7 08:18:53 1997 +++ linux/arch/m68k/amiga/config.c Thu Feb 12 16:30:12 1998 @@ -31,13 +31,13 @@ #include #include -u_long amiga_model; -u_long amiga_eclock; -u_long amiga_masterclock; -u_long amiga_colorclock; -u_long amiga_chipset; -u_char amiga_vblank; -u_char amiga_psfreq; +unsigned long amiga_model; +unsigned long amiga_eclock; +unsigned long amiga_masterclock; +unsigned long amiga_colorclock; +unsigned long amiga_chipset; +unsigned char amiga_vblank; +unsigned char amiga_psfreq; struct amiga_hw_present amiga_hw_present; static const char *amiga_models[] = { @@ -54,8 +54,10 @@ /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); -extern int amiga_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id); +extern int amiga_request_irq (unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); extern void amiga_free_irq (unsigned int irq, void *dev_id); extern void amiga_enable_irq (unsigned int); extern void amiga_disable_irq (unsigned int); @@ -69,28 +71,50 @@ static int amiga_hwclk (int, struct hwclk_time *); static int amiga_set_clock_mmss (unsigned long); extern void amiga_mksound( unsigned int count, unsigned int ticks ); -#ifdef CONFIG_BLK_DEV_FD -extern int amiga_floppy_init (void); +#ifdef CONFIG_AMIGA_FLOPPY extern void amiga_floppy_setup(char *, int *); #endif static void amiga_reset (void); -static void amiga_wait_key(void); +static int amiga_wait_key (struct console *co); extern struct consw fb_con; -extern struct fb_info *amiga_fb_init(long *); extern void zorro_init(void); extern void amiga_init_sound(void); static void amiga_savekmsg_init(void); -static void amiga_mem_console_write(const char *b, unsigned int count); -static void amiga_serial_console_write(const char *s, unsigned int count); +static void amiga_mem_console_write(struct console *co, const char *b, + unsigned int count); +void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count); static void amiga_debug_init(void); - -extern void amiga_video_setup(char *, int *); -extern void amiga_init_sound(void); +#ifdef CONFIG_HEARTBEAT +static void amiga_heartbeat(int on); +#endif static struct console amiga_console_driver = { - NULL, NULL, amiga_wait_key + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + amiga_wait_key, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL }; +#ifdef CONFIG_MAGIC_SYSRQ +static char amiga_sysrq_xlate[128] = + "\0001234567890-=\\\000\000" /* 0x00 - 0x0f */ + "qwertyuiop[]\000123" /* 0x10 - 0x1f */ + "asdfghjkl;'\000\000456" /* 0x20 - 0x2f */ + "\000zxcvbnm,./\000+789" /* 0x30 - 0x3f */ + " \177\t\r\r\000\177\000\000\000-\000\000\000\000\000" /* 0x40 - 0x4f */ + "\000\201\202\203\204\205\206\207\210\211()/*+\000" /* 0x50 - 0x5f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif + extern void (*kd_mksound)(unsigned int, unsigned int); /* @@ -100,7 +124,7 @@ int amiga_parse_bootinfo(const struct bi_record *record) { int unknown = 0; - const u_long *data = record->data; + const unsigned long *data = record->data; switch (record->tag) { case BI_AMIGA_MODEL: @@ -120,11 +144,11 @@ break; case BI_AMIGA_VBLANK: - amiga_vblank = *(const u_char *)data; + amiga_vblank = *(const unsigned char *)data; break; case BI_AMIGA_PSFREQ: - amiga_psfreq = *(const u_char *)data; + amiga_psfreq = *(const unsigned char *)data; break; case BI_AMIGA_AUTOCON: @@ -147,10 +171,10 @@ } /* - * Setup the Amiga configuration info + * Identify builtin hardware */ -__initfunc(void config_amiga(void)) +__initfunc(static void amiga_identify(void)) { /* Fill in some default values, if necessary */ if (amiga_eclock == 0) @@ -158,8 +182,6 @@ memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); - amiga_debug_init(); - printk("Amiga hardware found: "); if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) printk("[%s] ", amiga_models[amiga_model-AMI_500]); @@ -171,6 +193,7 @@ case AMI_600: case AMI_1200: AMIGAHW_SET(A1200_IDE); + AMIGAHW_SET(PCMCIA); case AMI_500: case AMI_500PLUS: case AMI_1000: @@ -300,11 +323,22 @@ AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); - if (AMIGAHW_SET(ZORRO)) - printk("ZORRO%s ", AMIGAHW_SET(ZORRO3) ? "3" : ""); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); + if (AMIGAHW_PRESENT(ZORRO)) + printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); printk("\n"); #undef AMIGAHW_ANNOUNCE +} + + /* + * Setup the Amiga configuration info + */ + +__initfunc(void config_amiga(void)) +{ + amiga_debug_init(); + amiga_identify(); mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; @@ -338,15 +372,21 @@ mach_hwclk = amiga_hwclk; mach_set_clock_mmss = amiga_set_clock_mmss; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_init = amiga_floppy_init; +#ifdef CONFIG_AMIGA_FLOPPY mach_floppy_setup = amiga_floppy_setup; #endif mach_reset = amiga_reset; conswitchp = &fb_con; - mach_fb_init = amiga_fb_init; - mach_video_setup = amiga_video_setup; kd_mksound = amiga_mksound; +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 0x5f; /* HELP */ + mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */ + mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ + mach_sysrq_xlate = amiga_sysrq_xlate; +#endif +#ifdef CONFIG_HEARTBEAT + mach_heartbeat = amiga_heartbeat; +#endif /* Fill in the clock values (based on the 700 kHz E-Clock) */ amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ @@ -357,15 +397,51 @@ /* ensure that the DMA master bit is set */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + /* don't use Z2 RAM as system memory on Z3 capable machines */ + if (AMIGAHW_PRESENT(ZORRO3)) { + int i, j; + unsigned long z2mem = 0; + for (i = 0; i < m68k_num_memory; i++) + if (m68k_memory[i].addr < 16*1024*1024) { + if (i == 0) { + /* don't cut off the branch we're sitting on */ + printk("Warning: kernel runs in Zorro II memory\n"); + continue; + } + z2mem += m68k_memory[i].size; + m68k_num_memory--; + for (j = i; j < m68k_num_memory; j++) + m68k_memory[j] = m68k_memory[j+1]; + } + if (z2mem) + printk("%ldK of Zorro II memory will not be used as system memory\n", + z2mem>>10); + } + /* initialize chipram allocator */ amiga_chip_init (); + /* debugging using chipram */ + if (!strcmp( m68k_debug_device, "mem" )){ + if (!AMIGAHW_PRESENT(CHIP_RAM)) + printk("Warning: no chipram present for debugging\n"); + else { + amiga_savekmsg_init(); + amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); + } + } + + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); + /* * if it is an A3000, set the magic bit that forces * a hard rekick */ if (AMIGAHW_PRESENT(MAGIC_REKICK)) - *(u_char *)ZTWO_VADDR(0xde0002) |= 0x80; + *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; zorro_init(); #ifdef CONFIG_ZORRO @@ -373,7 +449,7 @@ * Identify all known AutoConfig Expansion Devices */ zorro_identify(); -#endif /* CONFIG_ZORRO */ +#endif } static unsigned short jiffy_ticks; @@ -383,7 +459,7 @@ { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; - ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ + ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; @@ -392,7 +468,8 @@ * Please don't change this to use ciaa, as it interferes with the * SCSI code. We'll have to take a look at this later */ - request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, "timer", NULL); + request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, + "timer", NULL); /* start timer */ ciab.cra |= 0x11; } @@ -462,11 +539,12 @@ *monp = tod->month1 * 10 + tod->month2; *yearp = tod->year1 * 10 + tod->year2; - if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)) + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12) *hourp = 0; else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12) *hourp += 12; + } tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; } @@ -521,11 +599,12 @@ t->mon = tod->month1 * 10 + tod->month2 - 1; t->year = tod->year1 * 10 + tod->year2; - if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)) + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12) t->hour = 0; else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12) t->hour += 12; + } } else { tod->second1 = t->sec / 10; tod->second2 = t->sec % 10; @@ -589,7 +668,7 @@ return 0; } -static void amiga_wait_key (void) +static int amiga_wait_key (struct console *co) { int i; @@ -613,6 +692,7 @@ if (ciaa.pra & 0x40) break; } + return 0; } void dbprintf(const char *fmt , ...) @@ -707,16 +787,17 @@ #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ struct savekmsg { - u_long magic1; /* SAVEKMSG_MAGIC1 */ - u_long magic2; /* SAVEKMSG_MAGIC2 */ - u_long magicptr; /* address of magic1 */ - u_long size; + unsigned long magic1; /* SAVEKMSG_MAGIC1 */ + unsigned long magic2; /* SAVEKMSG_MAGIC2 */ + unsigned long magicptr; /* address of magic1 */ + unsigned long size; char data[0]; }; static struct savekmsg *savekmsg = NULL; -static void amiga_mem_console_write(const char *s, unsigned int count) +static void amiga_mem_console_write(struct console *co, const char *s, + unsigned int count) { if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { memcpy(savekmsg->data+savekmsg->size, s, count); @@ -740,7 +821,8 @@ ; } -static void amiga_serial_console_write(const char *s, unsigned int count) +void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count) { while (count--) { if (*s == '\n') @@ -752,19 +834,27 @@ #ifdef CONFIG_SERIAL_CONSOLE void amiga_serial_puts(const char *s) { - amiga_serial_console_write(s, strlen(s)); + amiga_serial_console_write(NULL, s, strlen(s)); +} + +int amiga_serial_console_wait_key(struct console *co) +{ + int ch; + + while (!(custom.intreqr & IF_RBF)) + barrier(); + ch = custom.serdatr & 0xff; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return ch; } -void amiga_serial_gets(char *s, int len) +void amiga_serial_gets(struct console *co, char *s, int len) { int ch, cnt = 0; while (1) { - while (!(custom.intreqr & IF_RBF)) - barrier(); - ch = custom.serdatr & 0xff; - /* clear the interrupt, so that another character can be read */ - custom.intreq = IF_RBF; + ch = amiga_serial_console_wait_key(co); /* Check for backspace. */ if (ch == 8 || ch == 127) { @@ -803,17 +893,19 @@ if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ amiga_console_driver.write = amiga_serial_console_write; - } else if (!strcmp( m68k_debug_device, "mem" )) { - amiga_savekmsg_init(); - amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); } - register_console(&amiga_console_driver); - - /* our beloved beeper */ - if (AMIGAHW_PRESENT(AMI_AUDIO)) - amiga_init_sound(); } +#ifdef CONFIG_HEARTBEAT +static void amiga_heartbeat(int on) +{ + if (on) + ciaa.pra &= ~2; + else + ciaa.pra |= 2; +} +#endif /* * Amiga specific parts of /proc @@ -888,6 +980,7 @@ AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); if (AMIGAHW_PRESENT(ZORRO)) len += sprintf(buffer+len, "\tZorro%s AutoConfig: %d Expansion Device%s\n", AMIGAHW_PRESENT(ZORRO3) ? " III" : "", diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/s3blit.h linux/arch/m68k/amiga/s3blit.h --- v2.1.86/linux/arch/m68k/amiga/s3blit.h Sun May 19 21:54:25 1996 +++ linux/arch/m68k/amiga/s3blit.h Wed Dec 31 16:00:00 1969 @@ -1,74 +0,0 @@ -/* s3 commands */ -#define S3_BITBLT 0xc011 -#define S3_TWOPOINTLINE 0x2811 -#define S3_FILLEDRECT 0x40b1 - -#define S3_FIFO_EMPTY 0x0400 -#define S3_HDW_BUSY 0x0200 - -/* Enhanced register mapping (MMIO mode) */ - -#define S3_READ_SEL 0xbee8 /* offset f */ -#define S3_MULT_MISC 0xbee8 /* offset e */ -#define S3_ERR_TERM 0x92e8 -#define S3_FRGD_COLOR 0xa6e8 -#define S3_BKGD_COLOR 0xa2e8 -#define S3_PIXEL_CNTL 0xbee8 /* offset a */ -#define S3_FRGD_MIX 0xbae8 -#define S3_BKGD_MIX 0xb6e8 -#define S3_CUR_Y 0x82e8 -#define S3_CUR_X 0x86e8 -#define S3_DESTY_AXSTP 0x8ae8 -#define S3_DESTX_DIASTP 0x8ee8 -#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */ -#define S3_MAJ_AXIS_PCNT 0x96e8 -#define S3_CMD 0x9ae8 -#define S3_GP_STAT 0x9ae8 -#define S3_ADVFUNC_CNTL 0x4ae8 -#define S3_WRT_MASK 0xaae8 -#define S3_RD_MASK 0xaee8 - -/* Enhanced register mapping (Packed MMIO mode, write only) */ -#define S3_ALT_CURXY 0x8100 -#define S3_ALT_CURXY2 0x8104 -#define S3_ALT_STEP 0x8108 -#define S3_ALT_STEP2 0x810c -#define S3_ALT_ERR 0x8110 -#define S3_ALT_CMD 0x8118 -#define S3_ALT_MIX 0x8134 -#define S3_ALT_PCNT 0x8148 -#define S3_ALT_PAT 0x8168 - -/* Drawing modes */ -#define S3_NOTCUR 0x0000 -#define S3_LOGICALZERO 0x0001 -#define S3_LOGICALONE 0x0002 -#define S3_LEAVEASIS 0x0003 -#define S3_NOTNEW 0x0004 -#define S3_CURXORNEW 0x0005 -#define S3_NOT_CURXORNEW 0x0006 -#define S3_NEW 0x0007 -#define S3_NOTCURORNOTNEW 0x0008 -#define S3_CURORNOTNEW 0x0009 -#define S3_NOTCURORNEW 0x000a -#define S3_CURORNEW 0x000b -#define S3_CURANDNEW 0x000c -#define S3_NOTCURANDNEW 0x000d -#define S3_CURANDNOTNEW 0x000e -#define S3_NOTCURANDNOTNEW 0x000f - -#define S3_CRTC_ADR 0x03d4 -#define S3_CRTC_DATA 0x03d5 - -#define S3_REG_LOCK2 0x39 -#define S3_HGC_MODE 0x45 - -#define S3_HWGC_ORGX_H 0x46 -#define S3_HWGC_ORGX_L 0x47 -#define S3_HWGC_ORGY_H 0x48 -#define S3_HWGC_ORGY_L 0x49 -#define S3_HWGC_DX 0x4e -#define S3_HWGC_DY 0x4f - - -#define S3_LAW_CTL 0x58 diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c --- v2.1.86/linux/arch/m68k/amiga/zorro.c Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/amiga/zorro.c Thu Feb 12 16:30:12 1998 @@ -13,996 +13,1221 @@ #include #include #include -#include -#include #include #include #include +#include #ifdef CONFIG_ZORRO - /* - * Zorro Expansion Device Manufacturers and Products - */ + /* + * Zorro Expansion Device Manufacturers and Products + */ struct Manufacturer { - char *Name; - u_short ID; - u_short NumProd; - struct Product *Products; + const char *Name; + u_short Manuf; + u_short NumProd; + const struct Product *Products; }; struct Product { - char *Name; - u_char ID; + const char *Name; + u_char Class; + u_char Prod; }; struct GVP_Product { - char *Name; - enum GVP_ident ID; + const char *Name; + u_char Class; + u_char EPC; }; - /* - * Macro's to make life easier - */ - -#define BEGIN_PROD(id) static struct Product Prod_##id[] = { -#define PROD(name, id) \ - { name, PROD_##id }, - -#define BEGIN_GVP_PROD static struct GVP_Product Ext_Prod_GVP[] = { -#define GVP_PROD(name, id) \ - { name, GVP_##id }, + /* + * Macro's to make life easier + */ + +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x))) + +#define BEGIN_PROD(id) \ + static struct Product Prod_##id[] = { +#define PROD(name, class, id) \ + { name, ZORRO_CLASS_##class, ZORRO_PROD(ZORRO_PROD_##id) }, + +#define BEGIN_GVP_PROD \ + static struct GVP_Product Ext_Prod_GVP[] = { +#define GVP_PROD(name, class, id) \ + { name, ZORRO_CLASS_##class, ZORRO_EPC(ZORRO_PROD_##id) }, -#define BEGIN_MANUF static struct Manufacturer Manufacturers[] = { +#define BEGIN_MANUF \ + static struct Manufacturer Manufacturers[] = { #define MANUF(name, id) \ - { name, MANUF_##id, sizeof(Prod_##id)/sizeof(struct Product), Prod_##id }, + { name, ZORRO_MANUF_##id, ARRAYSIZE(Prod_##id), Prod_##id }, -#define END }; +#define END \ + }; - /* - * Known Zorro Expansion Devices - * - * Warning: Make sure the Manufacturer and Product names are not too - * long (max. 80 characters per board identification line) - */ + /* + * Recognized Zorro Expansion Devices + */ + +BEGIN_PROD(PACIFIC_PERIPHERALS) + PROD("SE 2000 A500", HD, PACIFIC_PERIPHERALS_SE_2000_A500) + PROD(NULL, SCSI, PACIFIC_PERIPHERALS_SCSI) +END -BEGIN_PROD(PACIFIC) - PROD("SE 2000 A500", SE_2000_A500) - PROD("HD Controller", PACIFIC_HD) +BEGIN_PROD(MACROSYSTEMS_USA_2) + PROD("Warp Engine", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE) END -BEGIN_PROD(KUPKE) - PROD("Golem RAM Box 2MB", GOLEM_BOX_2) +BEGIN_PROD(KUPKE_1) + PROD("Golem RAM Box 2MB", RAM, KUPKE_GOLEM_RAM_BOX_2MB) END BEGIN_PROD(MEMPHIS) - PROD("Stormbringer", STORMBRINGER) + PROD("Stormbringer", TURBO, MEMPHIS_STORMBRINGER) END BEGIN_PROD(3_STATE) - PROD("Megamix 2000 RAM", MEGAMIX_2000) + PROD("Megamix 2000", RAM, 3_STATE_MEGAMIX_2000) +END + +BEGIN_PROD(COMMODORE_BRAUNSCHWEIG) + PROD("A2088 XT/A2286 AT", BRIDGE, CBM_A2088_A2286) + PROD("A2286 AT", BRIDGE, CBM_A2286) + PROD("A4091", SCSI, CBM_A4091_1) + PROD("A2386-SX", BRIDGE, CBM_A2386SX_1) +END + +BEGIN_PROD(COMMODORE_WEST_CHESTER_1) + PROD("A2090/A2090A", SCSI, CBM_A2090A) + PROD("A590/A2091", SCSI, CBM_A590_A2091_1) + PROD("A590/A2091", SCSI, CBM_A590_A2091_2) + PROD("A2090B 2090 Autoboot", SCSI, CBM_A2090B) + PROD("A2060", ARCNET, CBM_A2060) + PROD("A590/A2052/A2058/A2091", RAM, CBM_A590_A2052_A2058_A2091) + PROD("A560", RAM, CBM_A560_RAM) + PROD("A2232 Prototype", MULTIIO, CBM_A2232_PROTOTYPE) + PROD("A2232", MULTIIO, CBM_A2232) + PROD("A2620 68020/RAM", TURBO_RAM, CBM_A2620) + PROD("A2630 68030/RAM", TURBO_RAM, CBM_A2630) + PROD("A4091", SCSI, CBM_A4091_2) + PROD("A2065", ETHERNET, CBM_A2065_1) + PROD("Romulator Card", UNKNOWN, CBM_ROMULATOR) + PROD("A3000 Test Fixture", MISC, CBM_A3000_TEST_FIXTURE) + PROD("A2386-SX", BRIDGE, CBM_A2386SX_2) + PROD("A2065", ETHERNET, CBM_A2065_2) +END + +BEGIN_PROD(COMMODORE_WEST_CHESTER_2) + PROD("A2090/A2090A Combitec/MacroSystem", SCSI, CBM_A2090A_CM) +END + +BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2) + PROD("EXP8000", RAM, PPS_EXP8000) +END + +BEGIN_PROD(KOLFF_COMPUTER_SUPPLIES) + PROD("KCS Power PC Board", BRIDGE, KCS_POWER_PC_BOARD) END -BEGIN_PROD(COMMODORE2) - PROD("A2088 XT Bridgeboard", A2088) - PROD("A2286 AT Bridgeboard", A2286) - PROD("A4091 SCSI Controller", A4091_2) - PROD("A2386-SX Bridgeboard", A2386SX) -END - -BEGIN_PROD(COMMODORE) - PROD("A2090/A2090A HD Controller", A2090A) - PROD("A590 SCSI Controller", A590) - PROD("A2091 SCSI Controller", A2091) - PROD("A2090B 2090 Autoboot Card", A2090B) - PROD("A2060 Arcnet Card", ARCNET) - PROD("A2052/58.RAM | 590/2091.RAM", CBMRAM) - PROD("A560 Memory Module", A560RAM) - PROD("A2232 Serial Prototype", A2232PROTO) - PROD("A2232 Serial Production", A2232) - PROD("A2620 68020/RAM Card", A2620) - PROD("A2630 68030/RAM Card", A2630) - PROD("A4091 SCSI Controller", A4091) - PROD("A2065 Ethernet Card", A2065_2) - PROD("Romulator Card", ROMULATOR) - PROD("A3000 Test Fixture", A3000TESTFIX) - PROD("A2386-SX Bridgeboard", A2386SX_2) - PROD("A2065 Ethernet Card", A2065) -END - -BEGIN_PROD(COMMODORE3) - PROD("A2090A Combitec/MacroSystem", A2090A_CM) -END - -BEGIN_PROD(KCS) - PROD("KCS Power PC Board", POWER_BOARD) -END - -BEGIN_PROD(CARDCO) - PROD("Kronos 2000 SCSI Controller", KRONOS_2000_SCSI) - PROD("A1000 SCSI Controller", A1000_SCSI) - PROD("Escort SCSI Controller", ESCORT_SCSI) - PROD("Cardco A2410 Hires Graphics card", CC_A2410) +BEGIN_PROD(CARDCO_1) + PROD("Kronos 2000", SCSI, CARDCO_KRONOS_2000_1) + PROD("A1000", SCSI, CARDCO_A1000_1) + PROD("Escort", SCSI, CARDCO_ESCORT) + PROD("A2410 HiRes", GFX, CARDCO_A2410) END BEGIN_PROD(A_SQUARED) - PROD("Live! 2000", LIVE_2000) + PROD("Live! 2000", VIDEO, A_SQUARED_LIVE_2000) END -BEGIN_PROD(COMSPEC) - PROD("AX2000", AX2000) +BEGIN_PROD(COMSPEC_COMMUNICATIONS) + PROD("AX2000", RAM, COMSPEC_COMMUNICATIONS_AX2000) END -BEGIN_PROD(ANAKIN) - PROD("Easyl Tablet", EASYL) +BEGIN_PROD(ANAKIN_RESEARCH) + PROD("Easyl", TABLET, ANAKIN_RESEARCH_EASYL) END BEGIN_PROD(MICROBOTICS) - PROD("StarBoard II", STARBOARD_II) - PROD("StarDrive", STARDRIVE) - PROD("8-Up (Rev A)", 8_UP_A) - PROD("8-Up (Rev Z)", 8_UP_Z) - PROD("Delta Card RAM", DELTA_RAM) - PROD("8-Star RAM", 8_STAR_RAM) - PROD("8-Star", 8_STAR) - PROD("VXL RAM", VXL_RAM) - PROD("VXL-30 Turbo Board", VXL_30) - PROD("Delta Card", DELTA) - PROD("MBX 1200", MBX_1200) - PROD("Hardframe 2000", HARDFRAME_2000) - PROD("MBX 1200", MBX_1200_2) + PROD("StarBoard II", RAM, MICROBOTICS_STARBOARD_II) + PROD("StarDrive", SCSI, MICROBOTICS_STARDRIVE) + PROD("8-Up (Rev A)", RAM, MICROBOTICS_8_UP_A) + PROD("8-Up (Rev Z)", RAM, MICROBOTICS_8_UP_Z) + PROD("Delta", RAM, MICROBOTICS_DELTA_RAM) + PROD("8-Star", RAM, MICROBOTICS_8_STAR_RAM) + PROD("8-Star", MISC, MICROBOTICS_8_STAR) + PROD("VXL RAM*32", RAM, MICROBOTICS_VXL_RAM_32) + PROD("VXL-30", TURBO, MICROBOTICS_VXL_68030) + PROD("Delta", MISC, MICROBOTICS_DELTA) + PROD("MBX 1200/1200z", RAM, MICROBOTICS_MBX_1200_1200Z_RAM) + PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_1) + PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_2) + PROD("MBX 1200/1200z", MISC, MICROBOTICS_MBX_1200_1200Z) END -BEGIN_PROD(ACCESS) +BEGIN_PROD(ACCESS_ASSOCIATES_ALEGRA) END -BEGIN_PROD(EXPANSION_TECH) +BEGIN_PROD(EXPANSION_TECHNOLOGIES) END BEGIN_PROD(ASDG) - PROD("Memory Expansion", ASDG_MEMORY) - PROD("Memory Expansion", ASDG_MEMORY_2) - PROD("Lan Rover Ethernet", LAN_ROVER) - PROD("Twin-X Serial Card", TWIN_X) + PROD(NULL, RAM, ASDG_MEMORY_1) + PROD(NULL, RAM, ASDG_MEMORY_2) + PROD("EB-920 Lan Rover", ETHERNET, ASDG_EB920_LAN_ROVER) + PROD("GPIB/Dual IEEE-488/Twin-X", MULTIIO, ASDG_GPIB_DUALIEEE488_TWIN_X) END -BEGIN_PROD(IMTRONICS) - PROD("Hurricane 2800 68030", HURRICANE_2800) - PROD("Hurricane 2800 68030", HURRICANE_2800_2) +BEGIN_PROD(IMTRONICS_1) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_1) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_2) END -BEGIN_PROD(UNIV_OF_LOWELL) - PROD("A2410 Hires Graphics Card", A2410) +BEGIN_PROD(CBM_UNIVERSITY_OF_LOWELL) + PROD("A2410 HiRes", GFX, CBM_A2410) END BEGIN_PROD(AMERISTAR) - PROD("A2065 Ethernet Card", AMERISTAR2065) - PROD("A560 Arcnet Card", A560) - PROD("A4066 Ethernet Card", A4066) + PROD("A2065", ETHERNET, AMERISTAR_A2065) + PROD("A560", ARCNET, AMERISTAR_A560) + PROD("A4066", ETHERNET, AMERISTAR_A4066) END BEGIN_PROD(SUPRA) - PROD("SupraDrive 4x4 SCSI Controller", SUPRADRIVE_4x4) - PROD("2000 DMA HD", SUPRA_2000) - PROD("500 HD/RAM", SUPRA_500) - PROD("500XP/2000 RAM", SUPRA_500XP) - PROD("500RX/2000 RAM", SUPRA_500RX) - PROD("2400zi Modem", SUPRA_2400ZI) - PROD("Wordsync SCSI Controller", WORDSYNC) - PROD("Wordsync II SCSI Controller", WORDSYNC_II) - PROD("2400zi+ Modem", SUPRA_2400ZIPLUS) + PROD("SupraDrive 4x4", SCSI, SUPRA_SUPRADRIVE_4x4) + PROD("1000", RAM, SUPRA_1000_RAM) + PROD("2000 DMA", SCSI, SUPRA_2000_DMA) + PROD("500", SCSI_RAM, SUPRA_500) + PROD("500", SCSI, SUPRA_500_SCSI) + PROD("500XP/2000", RAM, SUPRA_500XP_2000_RAM) + PROD("500RX/2000", RAM, SUPRA_500RX_2000_RAM) + PROD("2400zi", MODEM, SUPRA_2400ZI) + PROD("500XP/SupraDrive WordSync", SCSI, SUPRA_500XP_SUPRADRIVE_WORDSYNC) + PROD("SupraDrive WordSync II", SCSI, SUPRA_SUPRADRIVE_WORDSYNC_II) + PROD("2400zi+", MODEM, SUPRA_2400ZIPLUS) END -BEGIN_PROD(CSA) - PROD("Magnum 40 SCSI Controller", MAGNUM) - PROD("12 Gauge SCSI Controller", 12GAUGE) +BEGIN_PROD(COMPUTER_SYSTEMS_ASSOCIATES) + PROD("Magnum 40", TURBO_SCSI, CSA_MAGNUM) + PROD("12 Gauge", SCSI, CSA_12_GAUGE) END -BEGIN_PROD(MTEC2) - PROD("AT500 RAM", AT500_2) +BEGIN_PROD(MARC_MICHAEL_GROTH) END -BEGIN_PROD(GVP3) - PROD("Impact SCSI/Memory", IMPACT) +BEGIN_PROD(M_TECH) + PROD("AT500", RAM, MTEC_AT500_1) +END + +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_1) + PROD("Impact Series I", SCSI_RAM, GVP_IMPACT_SERIES_I) END BEGIN_PROD(BYTEBOX) - PROD("A500", BYTEBOX_A500) + PROD("A500", UNKNOWN, BYTEBOX_A500) END -BEGIN_PROD(POWER_COMPUTING) - PROD("DKB 3128 RAM", DKB_3128) - PROD("Rapid Fire SCSI Controller", RAPID_FIRE) - PROD("DKB 1202 RAM", DKB_1202) - PROD("DKB Cobra / Viper II Turbo Board", VIPER_II_COBRA) - PROD("WildFire 060 Turbo Board", WILDFIRE_060) - PROD("WildFire 060 Turbo Board", WILDFIRE_060_2) -END - -BEGIN_PROD(GVP) - PROD("Impact Series-I SCSI 4K", IMPACT_I_4K) - PROD("Impact Series-I SCSI 16K/2", IMPACT_I_16K_2) - PROD("Impact Series-I SCSI 16K/3", IMPACT_I_16K_3) - PROD("Impact 3001 IDE", IMPACT_3001_IDE) -/* PROD("Impact 3001 RAM", IMPACT_3001_RAM) */ - PROD("Generic GVP product", GVP) - PROD("Series II SCSI Controller", GVPIISCSI) - PROD("Series II SCSI Controller", GVPIISCSI_2) - PROD("Series II RAM", GVPIIRAM) - PROD("A2000 68030 Turbo Board", GVP_A2000_030) -/* PROD("Impact 3001 IDE", IMPACT_3001_IDE_2) */ - PROD("GFORCE 040 with SCSI Controller", GFORCE_040_SCSI) - PROD("IV-24 Graphics Board", GVPIV_24) - PROD("GFORCE 040 Turbo Board", GFORCE_040) -/* PROD("I/O Extender", GVPIO_EXT) */ -END - -BEGIN_GVP_PROD - GVP_PROD("GFORCE 040", GFORCE_040) - GVP_PROD("GFORCE 040 with SCSI controller", GFORCE_040_SCSI) - GVP_PROD("A1291 SCSI controller", A1291_SCSI) - GVP_PROD("COMBO 030 R4", COMBO_R4) - GVP_PROD("COMBO 030 R4 with SCSI controller", COMBO_R4_SCSI) - GVP_PROD("Phone Pak", PHONEPAK) - GVP_PROD("IO-Extender", IOEXT) - GVP_PROD("GFORCE 030", GFORCE_030) - GVP_PROD("GFORCE 030 with SCSI controller", GFORCE_030_SCSI) - GVP_PROD("A530", A530) - GVP_PROD("A530 with SCSI", A530_SCSI) - GVP_PROD("COMBO 030 R3", COMBO_R3) - GVP_PROD("COMBO 030 R3 with SCSI controller", COMBO_R3_SCSI) - GVP_PROD("SERIES-II SCSI controller", SERIESII) +BEGIN_PROD(DKB_POWER_COMPUTING) + PROD("SecureKey", UNKNOWN, DKB_POWER_COMPUTING_SECUREKEY) + PROD("DKM 3128", RAM, DKB_POWER_COMPUTING_DKM_3128) + PROD("Rapid Fire", SCSI, DKB_POWER_COMPUTING_RAPID_FIRE) + PROD("DKM 1202", FPU_RAM, DKB_POWER_COMPUTING_DKM_1202) + PROD("Cobra/Viper II 68EC030", TURBO, DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030) + PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_1) + PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_2) +END + +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_2) + PROD("Impact Series I (4K)", SCSI, GVP_IMPACT_SERIES_I_4K) + PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_2) + PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_3) + PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_1) + PROD("Impact 3001", RAM, GVP_IMPACT_3001_RAM) + PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_1) +/* PROD(NULL, UNKNOWN, GVP_EPC_BASE) */ + PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_2) +/* PROD("A2000 030", TURBO, GVP_A2000_030) */ +/* PROD("GForce 040", TURBO_SCSI, GFORCE_040_SCSI_2) */ + PROD("GForce 040/060", TURBO_SCSI, GVP_GFORCE_040_060) + PROD("Impact Vision 24", GFX, GVP_IMPACT_VISION_24) + PROD("GForce 040", TURBO, GVP_GFORCE_040_2) +END + +BEGIN_GVP_PROD /* ZORRO_PROD_GVP_EPC_BASE */ + GVP_PROD("GForce 040", TURBO, GVP_GFORCE_040_1) + GVP_PROD("GForce 040", TURBO_SCSI, GVP_GFORCE_040_SCSI_1) + GVP_PROD("A1291", SCSI, GVP_A1291) + GVP_PROD("Combo 030 R4", TURBO, GVP_COMBO_030_R4) + GVP_PROD("Combo 030 R4", TURBO_SCSI, GVP_COMBO_030_R4_SCSI) + GVP_PROD("Phone Pak", UNKNOWN, GVP_PHONEPAK) + GVP_PROD("IO-Extender", MULTIIO, GVP_IO_EXTENDER) + GVP_PROD("GForce 030", TURBO, GVP_GFORCE_030) + GVP_PROD("GForce 030", TURBO_SCSI, GVP_GFORCE_030_SCSI) + GVP_PROD("A530", TURBO, GVP_A530) + GVP_PROD("A530", TURBO_SCSI, GVP_A530_SCSI) + GVP_PROD("Combo 030 R3", TURBO, GVP_COMBO_030_R3) + GVP_PROD("Combo 030 R3", TURBO_SCSI, GVP_COMBO_030_R3_SCSI) + GVP_PROD("Series-II", SCSI, GVP_SERIES_II) END -BEGIN_PROD(SYNERGY) +BEGIN_PROD(CALIFORNIA_ACCESS_SYNERGY) + PROD("Malibu", SCSI, CALIFORNIA_ACCESS_SYNERGY_MALIBU) END BEGIN_PROD(XETEC) - PROD("FastCard SCSI Controller", FASTCARD_SCSI) - PROD("FastCard RAM", FASTCARD_RAM) + PROD("FastCard", SCSI, XETEC_FASTCARD) + PROD("FastCard", RAM, XETEC_FASTCARD_RAM) + PROD("FastCard Plus", SCSI, XETEC_FASTCARD_PLUS) END -BEGIN_PROD(PPI) - PROD("Mercury Turbo Board", MERCURY) - PROD("PP&S A3000 68040 Turbo Board", PPS_A3000_040) - PROD("PP&S A2000 68040 Turbo Board", PPS_A2000_040) - PROD("Zeus SCSI Controller", ZEUS) - PROD("PP&S A500 68040 Turbo Board", PPS_A500_040) +BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS) + PROD("Mercury", TURBO, PPS_MERCURY) + PROD("A3000 68040", TURBO, PPS_A3000_68040) + PROD("A2000 68040", TURBO, PPS_A2000_68040) + PROD("Zeus", TURBO_SCSI_RAM, PPS_ZEUS) + PROD("A500 68040", TURBO, PPS_A500_68040) END BEGIN_PROD(XEBEC) END -BEGIN_PROD(SPIRIT) - PROD("HDA 506 Harddisk", HDA_506) - PROD("OctaByte RAM", OCTABYTE_RAM) +BEGIN_PROD(SPIRIT_TECHNOLOGY) + PROD("Insider IN1000", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN1000) + PROD("Insider IN500", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN500) + PROD("SIN500", RAM, SPIRIT_TECHNOLOGY_SIN500) + PROD("HDA 506", HD, SPIRIT_TECHNOLOGY_HDA_506) + PROD("AX-S", MISC, SPIRIT_TECHNOLOGY_AX_S) + PROD("OctaByte", RAM, SPIRIT_TECHNOLOGY_OCTABYTE) + PROD("Inmate", SCSI_RAM, SPIRIT_TECHNOLOGY_INMATE) +END + +BEGIN_PROD(SPIRIT_TECHNOLOGY_2) END -BEGIN_PROD(BSC) - PROD("ALF 3 SCSI Controller", ALF_3_SCSI) +BEGIN_PROD(BSC_ALFADATA_1) + PROD("ALF 3", SCSI, BSC_ALF_3_1) END -BEGIN_PROD(BSC3) - PROD("ALF 2 SCSI Controller", ALF_2_SCSI) - PROD("ALF 2 SCSI Controller", ALF_2_SCSI_2) - PROD("ALF 3 SCSI Controller", ALF_3_SCSI_2) +BEGIN_PROD(BSC_ALFADATA_2) + PROD("ALF 2", SCSI, BSC_ALF_2_1) + PROD("ALF 2", SCSI, BSC_ALF_2_2) + PROD("ALF 3", SCSI, BSC_ALF_3_2) END -BEGIN_PROD(C_LTD) - PROD("Kronos SCSI Controller", KRONOS_SCSI) - PROD("A1000 SCSI Controller", A1000_SCSI_2) +BEGIN_PROD(CARDCO_2) + PROD("Kronos", SCSI, CARDCO_KRONOS_2000_2) + PROD("A1000", SCSI, CARDCO_A1000_2) END BEGIN_PROD(JOCHHEIM) - PROD("Jochheim RAM", JOCHHEIM_RAM) + PROD(NULL, RAM, JOCHHEIM_RAM) END -BEGIN_PROD(CHECKPOINT) - PROD("Serial Solution", SERIAL_SOLUTION) +BEGIN_PROD(CHECKPOINT_TECHNOLOGIES) + PROD("Serial Solution", SERIAL, CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION) +END + +BEGIN_PROD(EDOTRONIK) + PROD("IEEE-488 Interface Board", UNKNOWN, EDOTRONIK_IEEE_488) + PROD("CBM-8032 Board", UNKNOWN, EDOTRONIK_8032) + PROD(NULL, SERIAL, EDOTRONIK_MULTISERIAL) + PROD("24Bit Realtime Video Digitizer", UNKNOWN, EDOTRONIK_VIDEODIGITIZER) + PROD("32Bit Parallel I/O Interface", UNKNOWN, EDOTRONIK_PARALLEL_IO) + PROD("PIC Prototyping Board", UNKNOWN, EDOTRONIK_PIC_PROTOYPING) + PROD("16 Channel ADC Interface", UNKNOWN, EDOTRONIK_ADC) + PROD("VME-Bus Controller", UNKNOWN, EDOTRONIK_VME) + PROD("DSP96000 Realtime Data Acquisition", DSP, EDOTRONIK_DSP96000) +END + +BEGIN_PROD(NES_INC) + PROD(NULL, RAM, NES_INC_RAM) END BEGIN_PROD(ICD) - PROD("Advantage 2000 SCSI Controller", ADVANTAGE_2000) + PROD("Advantage 2000", SCSI, ICD_ADVANTAGE_2000_SCSI) + PROD("Advantage", IDE, ICD_ADVANTAGE_2000_SCSI) + PROD("Advantage 2080", RAM, ICD_ADVANTAGE_2080_RAM) +END + +BEGIN_PROD(KUPKE_2) + PROD("Omti", HD, KUPKE_OMTI) + PROD("Golem SCSI-II", SCSI, KUPKE_SCSI_II) + PROD("Golem Box", UNKNOWN, KUPKE_GOLEM_BOX) + PROD("030/882", TURBO, KUPKE_030_882) + PROD("Golem", SCSI, KUPKE_SCSI_AT) END -BEGIN_PROD(KUPKE2) - PROD("Golem SCSI-II Controller", KUPKE_SCSI_II) - PROD("Golem Box", GOLEM_BOX) - PROD("030/882 Turbo Board", KUPKE_TURBO) - PROD("Golem SCSI/AT Controller", KUPKE_SCSI_AT) +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_3) + PROD("A2000-RAM8/2", MISC, GVP_A2000_RAM8) + PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_2) END -BEGIN_PROD(GVP4) - PROD("A2000-RAM8/2", A2000_RAM8) +BEGIN_PROD(INTERWORKS_NETWORK) END -BEGIN_PROD(INTERWORKS_NET) +BEGIN_PROD(HARDITAL_SYNTHESIS) + PROD("TQM 68030+68882", TURBO, HARDITAL_SYNTHESIS_TQM_68030_68882) END -BEGIN_PROD(HARDITAL) - PROD("TQM 68030+68882 Turbo Board", TQM) +BEGIN_PROD(APPLIED_ENGINEERING) + PROD("DL2000", MODEM, APPLIED_ENGINEERING_DL2000) + PROD("RAM Works", RAM, APPLIED_ENGINEERING_RAM_WORKS) END -BEGIN_PROD(BSC2) - PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI) - PROD("Tandem AT-2008/508 IDE Controller", TANDEM) - PROD("Alpha RAM 1200", ALPHA_RAM_1200) - PROD("Oktagon 2008 RAM", OKTAGON_RAM) - PROD("Alfa Data MultiFace I", MULTIFACE_I) - PROD("Alfa Data MultiFace II", MULTIFACE_II) - PROD("Alfa Data MultiFace III", MULTIFACE_III) - PROD("Framebuffer", BSC_FRAEMBUFFER) - PROD("Graffiti Graphics Board (RAM)", GRAFFITI_RAM) - PROD("Graffiti Graphics Board (REG)", GRAFFITI_REG) - PROD("ISDN MasterCard", ISDN_MASTERCARD) - PROD("ISDN MasterCard II", ISDN_MASTERCARD_2) +BEGIN_PROD(BSC_ALFADATA_3) + PROD("Oktagon 2008", SCSI, BSC_OKTAGON_2008) + PROD("Tandem AT-2008/508", IDE, BSC_TANDEM_AT_2008_508) + PROD("Alpha RAM 1200", RAM, BSC_ALFA_RAM_1200) + PROD("Oktagon 2008", RAM, BSC_OKTAGON_2008_RAM) + PROD("MultiFace I", MULTIIO, BSC_MULTIFACE_I) + PROD("MultiFace II", MULTIIO, BSC_MULTIFACE_II) + PROD("MultiFace III", MULTIIO, BSC_MULTIFACE_III) + PROD("Framebuffer", MISC, BSC_FRAMEBUFFER) + PROD("Graffiti", GFXRAM, BSC_GRAFFITI_RAM) + PROD("Graffiti", GFX, BSC_GRAFFITI_REG) + PROD("ISDN MasterCard", ISDN, BSC_ISDN_MASTERCARD) + PROD("ISDN MasterCard II", ISDN, BSC_ISDN_MASTERCARD_II) END -BEGIN_PROD(ADV_SYS_SOFT) - PROD("Nexus SCSI Controller", NEXUS_SCSI) - PROD("Nexus RAM", NEXUS_RAM) +BEGIN_PROD(PHOENIX) + PROD("ST506", HD, PHOENIX_ST506) + PROD(NULL, SCSI, PHOENIX_SCSI) + PROD(NULL, RAM, PHOENIX_RAM) +END + +BEGIN_PROD(ADVANCED_STORAGE_SYSTEMS) + PROD("Nexus", SCSI, ADVANCED_STORAGE_SYSTEMS_NEXUS) + PROD("Nexus", RAM, ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM) END BEGIN_PROD(IMPULSE) - PROD("FireCracker 24", FIRECRACKER_24) + PROD("FireCracker 24", GFX, IMPULSE_FIRECRACKER_24) END BEGIN_PROD(IVS) - PROD("GrandSlam PIC 2 RAM", GRANDSLAM_PIC_2) - PROD("GrandSlam PIC 1 RAM", GRANDSLAM_PIC_1) - PROD("OverDrive HD", IVS_OVERDRIVE) - PROD("Trumpcard Classic SCSI Controller", TRUMPCARD_CLASSIC) - PROD("Trumpcard Pro SCSI Controller", TRUMPCARD_PRO) - PROD("Meta-4 RAM", META_4) - PROD("Wavetools Sound Board", WAVETOOLS) - PROD("Vector SCSI Controller", VECTOR) - PROD("Vector SCSI Controller", VECTOR_2) + PROD("GrandSlam PIC 2", RAM, IVS_GRANDSLAM_PIC_2) + PROD("GrandSlam PIC 1", RAM, IVS_GRANDSLAM_PIC_1) + PROD("OverDrive", HD, IVS_OVERDRIVE) + PROD("TrumpCard Classic", SCSI, IVS_TRUMPCARD_CLASSIC) + PROD("TrumpCard Pro/GrandSlam", SCSI, IVS_TRUMPCARD_PRO_GRANDSLAM) + PROD("Meta-4", RAM, IVS_META_4) + PROD("Wavetools", AUDIO, IVS_WAVETOOLS) + PROD("Vector", SCSI, IVS_VECTOR_1) + PROD("Vector", SCSI, IVS_VECTOR_2) END -BEGIN_PROD(VECTOR) - PROD("Connection Serial IO", CONNECTION) +BEGIN_PROD(VECTOR_1) + PROD("Connection", MULTIIO, VECTOR_CONNECTION_1) END BEGIN_PROD(XPERT_PRODEV) - PROD("Visiona Graphics Board (RAM)", VISIONA_RAM) - PROD("Visiona Graphics Board (REG)", VISIONA_REG) - PROD("Merlin Graphics Board (RAM)", MERLIN_RAM) - PROD("Merlin Graphics Board (REG)", MERLIN_REG) - PROD("Merlin Graphics Board (REG)", MERLIN_REG_2) + PROD("Visiona", GFXRAM, XPERT_PRODEV_VISIONA_RAM) + PROD("Visiona", GFX, XPERT_PRODEV_VISIONA_REG) + PROD("Merlin", GFXRAM, XPERT_PRODEV_MERLIN_RAM) + PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_1) + PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_2) END BEGIN_PROD(HYDRA_SYSTEMS) - PROD("Amiganet Board", AMIGANET) + PROD("Amiganet", ETHERNET, HYDRA_SYSTEMS_AMIGANET) END -BEGIN_PROD(SUNRIZE) - PROD("AD516 Audio", AD516) +BEGIN_PROD(SUNRIZE_INDUSTRIES) + PROD("AD1012", AUDIO, SUNRIZE_INDUSTRIES_AD1012) + PROD("AD516", AUDIO, SUNRIZE_INDUSTRIES_AD516) + PROD("DD512", AUDIO, SUNRIZE_INDUSTRIES_DD512) END BEGIN_PROD(TRICERATOPS) - PROD("Multi I/O Board", TRICERATOPS) + PROD(NULL, MULTIIO, TRICERATOPS_MULTI_IO) END BEGIN_PROD(APPLIED_MAGIC) - PROD("DMI Resolver Graphics Board", DMI_RESOLVER) - PROD("Digital Broadcaster", DIGITAL_BCASTER) + PROD("DMI Resolver", GFX, APPLIED_MAGIC_DMI_RESOLVER) + PROD("Digital Broadcaster", VIDEO, APPLIED_MAGIC_DIGITAL_BROADCASTER) END BEGIN_PROD(GFX_BASE) - PROD("GDA-1 Graphics Board (RAM)", GDA_1_RAM) - PROD("GDA-1 Graphics Board (REG)", GDA_1_REG) + PROD("GDA-1 VRAM", GFX, GFX_BASE_GDA_1_VRAM) + PROD("GDA-1", GFX, GFX_BASE_GDA_1) END BEGIN_PROD(ROCTEC) - PROD("RH 800C Hard Disk Controller", RH_800C) - PROD("RH 800C RAM", RH_800C_RAM) + PROD("RH 800C", HD, ROCTEC_RH_800C) + PROD("RH 800C", RAM, ROCTEC_RH_800C_RAM) +END + +BEGIN_PROD(KATO) + PROD("Melody MPEG", AUDIO, KATO_MELODY) + PROD("Rainbow II", GFX, HELFRICH_RAINBOW_II) /* ID clash!! */ + PROD("Rainbow III", GFX, HELFRICH_RAINBOW_III) /* ID clash!! */ +END + +BEGIN_PROD(ATLANTIS) END -BEGIN_PROD(HELFRICH1) - PROD("Rainbow3 Graphics Board", RAINBOW3) +BEGIN_PROD(PROTAR) END -BEGIN_PROD(SW_RESULT_ENTS) - PROD("GG2+ Bus Converter", GG2PLUS) +BEGIN_PROD(ACS) +END + +BEGIN_PROD(SOFTWARE_RESULTS_ENTERPRISES) + PROD("Golden Gate 2 Bus+", BRIDGE, SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS) END BEGIN_PROD(MASOBOSHI) - PROD("Master Card RAM", MASTER_CARD_RAM) - PROD("Master Card SCSI Controller", MASTER_CARD_SCSI) - PROD("MVD 819", MVD_819) + PROD("MasterCard SC201", RAM, MASOBOSHI_MASTER_CARD_SC201) + PROD("MasterCard MC702", SCSI_IDE, MASOBOSHI_MASTER_CARD_MC702) + PROD("MVD 819", UNKNOWN, MASOBOSHI_MVD_819) END -BEGIN_PROD(VILLAGE_TRONIC) - PROD("Domino Graphics Board (RAM)", DOMINO_RAM) - PROD("Domino Graphics Board (REG)", DOMINO_REG) - PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM) - PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG) - PROD("Picasso II/II+ Graphics Board (Segmented Mode)", PICASSO_II_SEGM) - PROD("Picassio IV Graphics Board", PICASSO_IV) - PROD("Picassio IV Graphics Board", PICASSO_IV_2) - PROD("Picassio IV Graphics Board", PICASSO_IV_3) - PROD("Picassio IV Graphics Board", PICASSO_IV_4) - PROD("Ariadne Ethernet Card", ARIADNE) +BEGIN_PROD(MAINHATTAN_DATA) + PROD(NULL, IDE, MAINHATTAN_DATA_IDE) END -BEGIN_PROD(UTILITIES_ULTD) - PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE) - PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE2) +BEGIN_PROD(VILLAGE_TRONIC) + PROD("Domino", GFXRAM, VILLAGE_TRONIC_DOMINO_RAM) + PROD("Domino", GFX, VILLAGE_TRONIC_DOMINO_REG) + PROD("Domino 16M Prototype", GFX, VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE) + PROD("Picasso II/II+", GFXRAM, VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM) + PROD("Picasso II/II+", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG) + PROD("Picasso II/II+ (Segmented Mode)", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE) + PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1) + PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2) + PROD("Picasso IV Z2", GFX, VILLAGE_TRONIC_PICASSO_IV_Z2_REG) + PROD("Picasso IV Z3", GFX, VILLAGE_TRONIC_PICASSO_IV_Z3) + PROD("Ariadne", ETHERNET_PARALLEL, VILLAGE_TRONIC_ARIADNE) +END + +BEGIN_PROD(UTILITIES_UNLIMITED) + PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE) + PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE2) END BEGIN_PROD(AMITRIX) - PROD("Multi-IO", AMITRIX_MULTI_IO) - PROD("CD-RAM Memory", AMITRIX_CD_RAM) + PROD(NULL, MULTIIO, AMITRIX_MULTI_IO) + PROD("CD-RAM", RAM, AMITRIX_CD_RAM) END BEGIN_PROD(ARMAX) - PROD("OmniBus Graphics Board", OMNIBUS) + PROD("OmniBus", GFX, ARMAX_OMNIBUS) END BEGIN_PROD(NEWTEK) - PROD("VideoToaster", VIDEOTOASTER) + PROD("VideoToaster", VIDEO, NEWTEK_VIDEOTOASTER) END -BEGIN_PROD(MTEC) - PROD("AT500 IDE Controller", AT500) - PROD("68030 Turbo Board", MTEC_68030) - PROD("68020i Turbo Board", MTEC_68020I) - PROD("A1200 T68030/42 RTC Turbo Board", MTEC_T1230) - PROD("8MB RAM", MTEC_RAM) +BEGIN_PROD(M_TECH_GERMANY) + PROD("AT500", IDE, MTEC_AT500_2) + PROD("68030", TURBO, MTEC_68030) + PROD("68020i", TURBO, MTEC_68020I) + PROD("A1200 T68030 RTC", TURBO, MTEC_A1200_T68030_RTC) + PROD("Viper Mk V/E-Matrix 530", TURBO_RAM, MTEC_VIPER_MK_V_E_MATRIX_530) + PROD("8MB", RAM, MTEC_8_MB_RAM) + PROD("Viper Mk V/E-Matrix 530 SCSI/IDE", SCSI_IDE, MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE) END -BEGIN_PROD(GVP2) - PROD("EGS 28/24 Spectrum Graphics Board (RAM)", SPECTRUM_RAM) - PROD("EGS 28/24 Spectrum Graphics Board (REG)", SPECTRUM_REG) +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_4) + PROD("EGS 28/24 Spectrum", GFX, GVP_EGS_28_24_SPECTRUM_REG) + PROD("EGS 28/24 Spectrum", GFXRAM, GVP_EGS_28_24_SPECTRUM_RAM) END -BEGIN_PROD(HELFRICH2) - PROD("Piccolo Graphics Board (RAM)", PICCOLO_RAM) - PROD("Piccolo Graphics Board (REG)", PICCOLO_REG) - PROD("PeggyPlus MPEG Decoder Board", PEGGY_PLUS) - PROD("VideoCruncher", VIDEOCRUNCHER) - PROD("SD64 Graphics Board (RAM)", SD64_RAM) - PROD("SD64 Graphics Board (REG)", SD64_REG) +BEGIN_PROD(APOLLO_1) + PROD("A1200", FPU_RAM, APOLLO_A1200) END -BEGIN_PROD(MACROSYSTEMS) - PROD("Warp Engine 40xx SCSI Controller", WARP_ENGINE) +BEGIN_PROD(HELFRICH_2) + PROD("Piccolo", GFXRAM, HELFRICH_PICCOLO_RAM) + PROD("Piccolo", GFX, HELFRICH_PICCOLO_REG) + PROD("PeggyPlus MPEG", VIDEO, HELFRICH_PEGGY_PLUS_MPEG) + PROD("VideoCruncher", VIDEO, HELFRICH_VIDEOCRUNCHER) + PROD("Piccolo SD64", GFXRAM, HELFRICH_SD64_RAM) + PROD("Piccolo SD64", GFX, HELFRICH_SD64_REG) END -BEGIN_PROD(ELBOX) - PROD("Elbox 1200/4 RAM", ELBOX_1200) +BEGIN_PROD(MACROSYSTEMS_USA) + PROD("Warp Engine 40xx", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE_40xx) END -BEGIN_PROD(HARMS_PROF) - PROD("030 plus", HARMS_030_PLUS) - PROD("3500 Turbo board", 3500_TURBO) +BEGIN_PROD(ELBOX_COMPUTER) + PROD("1200/4", RAM, ELBOX_COMPUTER_1200_4) +END + +BEGIN_PROD(HARMS_PROFESSIONAL) + PROD("030 Plus", TURBO, HARMS_PROFESSIONAL_030_PLUS) + PROD("3500 Professional", TURBO_RAM, HARMS_PROFESSIONAL_3500) END BEGIN_PROD(MICRONIK) - PROD("RCA 120 RAM", RCA_120) + PROD("RCA 120", RAM, MICRONIK_RCA_120) +END + +BEGIN_PROD(MICRONIK2) + PROD("Z3i A1200 Zorro III + SCSI", SCSI, MICRONIK2_Z3I) END -BEGIN_PROD(MEGA_MICRO) - PROD("SCRAM 500 SCSI Controller", SCRAM_500_SCSI) - PROD("SCRAM 500 RAM", SCRAM_500_RAM) +BEGIN_PROD(MEGAMICRO) + PROD("SCRAM 500", SCSI, MEGAMICRO_SCRAM_500) + PROD("SCRAM 500", RAM, MEGAMICRO_SCRAM_500_RAM) END -BEGIN_PROD(IMTRONICS2) - PROD("Hurricane 2800 68030", HURRICANE_2800_3) - PROD("Hurricane 2800 68030", HURRICANE_2800_4) +BEGIN_PROD(IMTRONICS_2) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_3) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_4) END -BEGIN_PROD(KUPKE3) - PROD("Golem HD 3000", GOLEM_3000) +BEGIN_PROD(INDIVIDUAL_COMPUTERS) + PROD("Buddha", IDE, INDIVIDUAL_COMPUTERS_BUDDHA) + PROD("Catweasel", IDE_FLOPPY, INDIVIDUAL_COMPUTERS_CATWEASEL) +END + +BEGIN_PROD(KUPKE_3) + PROD("Golem HD 3000", HD, KUPKE_GOLEM_HD_3000) END BEGIN_PROD(ITH) - PROD("ISDN-Master II", ISDN_MASTER_II) + PROD("ISDN-Master II", ISDN, ITH_ISDN_MASTER_II) END BEGIN_PROD(VMC) - PROD("ISDN Blaster Z2", ISDN_BLASTER_Z2) - PROD("HyperCom 4", HYPERCOM_4) + PROD("ISDN Blaster Z2", ISDN, VMC_ISDN_BLASTER_Z2) + PROD("HyperCom 4", MULTIIO, VMC_HYPERCOM_4) END BEGIN_PROD(INFORMATION) - PROD("ISDN Engine I", ISDN_ENGINE_I) + PROD("ISDN Engine I", ISDN, INFORMATION_ISDN_ENGINE_I) END BEGIN_PROD(VORTEX) - PROD("Golden Gate 80386SX Board", GOLDEN_GATE_386SX) - PROD("Golden Gate RAM", GOLDEN_GATE_RAM) - PROD("Golden Gate 80486 Board", GOLDEN_GATE_486) + PROD("Golden Gate 80386SX", BRIDGE, VORTEX_GOLDEN_GATE_80386SX) + PROD("Golden Gate", RAM, VORTEX_GOLDEN_GATE_RAM) + PROD("Golden Gate 80486", BRIDGE, VORTEX_GOLDEN_GATE_80486) END -BEGIN_PROD(DATAFLYER) - PROD("4000SX SCSI Controller", DATAFLYER_4000SXS) - PROD("4000SX RAM", DATAFLYER_4000SXR) +BEGIN_PROD(EXPANSION_SYSTEMS) + PROD("DataFlyer 4000SX", SCSI, EXPANSION_SYSTEMS_DATAFLYER_4000SX) + PROD("DataFlyer 4000SX", RAM, EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM) END BEGIN_PROD(READYSOFT) - PROD("AMax II/IV", AMAX) + PROD("AMax II/IV", MACEMU, READYSOFT_AMAX_II_IV) END BEGIN_PROD(PHASE5) - PROD("Blizzard RAM", BLIZZARD_RAM) - PROD("Blizzard", BLIZZARD) - PROD("Blizzard 1220-IV Turbo Board", BLIZZARD_1220_IV) - PROD("FastLane RAM", FASTLANE_RAM) - PROD("FastLane/Blizzard 1230-II/CyberSCSI", FASTLANE_SCSI) - PROD("Blizzard 1220/CyberStorm", CYBERSTORM_SCSI) - PROD("Blizzard 1230-III Turbo Board", BLIZZARD_1230_III) - PROD("Blizzard 1230-IV/1260 Turbo Board", BLIZZARD_1230_IV) - PROD("Blizzard 2060 SCSI Controller", BLIZZARD_2060SCSI) - PROD("CyberStorm Mk II", CYBERSTORM_II) - PROD("CyberVision64 Graphics Board", CYBERVISION) - PROD("CyberVision64-3D Graphics Board Prototype)", CYBERVISION3D_PRT) - PROD("CyberVision64-3D Graphics Board", CYBERVISION3D) + PROD("Blizzard", RAM, PHASE5_BLIZZARD_RAM) + PROD("Blizzard", TURBO, PHASE5_BLIZZARD) + PROD("Blizzard 1220-IV", TURBO, PHASE5_BLIZZARD_1220_IV) + PROD("FastLane Z3", RAM, PHASE5_FASTLANE_Z3_RAM) + PROD("Blizzard 1230-II/Fastlane Z3/CyberSCSI/CyberStorm060", TURBO_SCSI, PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) + PROD("Blizzard 1220/CyberStorm", TURBO_SCSI, PHASE5_BLIZZARD_1220_CYBERSTORM) + PROD("Blizzard 1230", TURBO, PHASE5_BLIZZARD_1230) + PROD("Blizzard 1230-IV/1260", TURBO, PHASE5_BLIZZARD_1230_IV_1260) + PROD("Blizzard 2060", TURBO, PHASE5_BLIZZARD_2060) + PROD("CyberStorm Mk II", FLASHROM, PHASE5_CYBERSTORM_MK_II) + PROD("CyberVision64", GFX, PHASE5_CYBERVISION64) + PROD("CyberVision64-3D Prototype", GFX, PHASE5_CYBERVISION64_3D_PROTOTYPE) + PROD("CyberVision64-3D", GFX, PHASE5_CYBERVISION64_3D) + PROD("CyberStorm Mk III", TURBO_SCSI, PHASE5_CYBERSTORM_MK_III) END BEGIN_PROD(DPS) - PROD("Personal Animation Recorder", DPS_PAR) + PROD("Personal Animation Recorder", VIDEO, DPS_PERSONAL_ANIMATION_RECORDER) END -BEGIN_PROD(APOLLO2) - PROD("A620 68020 Accelerator", A620) - PROD("A620 68020 Accelerator", A620_2) +BEGIN_PROD(APOLLO_2) + PROD("A620 68020", TURBO, APOLLO_A620_68020_1) + PROD("A620 68020", TURBO, APOLLO_A620_68020_2) END -BEGIN_PROD(APOLLO) - PROD("AT-Apollo", AT_APOLLO) - PROD("Turbo Board", APOLLO_TURBO) +BEGIN_PROD(APOLLO_3) + PROD("AT-Apollo", UNKNOWN, APOLLO_AT_APOLLO) + PROD("1230/1240/1260/2030/4040/4060", TURBO, APOLLO_1230_1240_1260_2030_4040_4060) END -BEGIN_PROD(PETSOFF) - PROD("Delfina DSP", DELFINA) +BEGIN_PROD(PETSOFF_LP) + PROD("Delfina", DSP, PETSOFF_LP_DELFINA) END BEGIN_PROD(UWE_GERLACH) - PROD("RAM/ROM", UG_RAM_ROM) + PROD("RAM/ROM", MISC, UWE_GERLACH_RAM_ROM) END -BEGIN_PROD(MACROSYSTEMS2) - PROD("Maestro", MAESTRO) - PROD("VLab", VLAB) - PROD("Maestro Pro", MAESTRO_PRO) - PROD("Retina Z2 Graphics Board", RETINA_Z2) - PROD("MultiEvolution", MULTI_EVOLUTION) - PROD("Toccata Sound Board", TOCCATA) - PROD("Retina Z3 Graphics Board", RETINA_Z3) - PROD("VLab Motion", VLAB_MOTION) - PROD("Altais Graphics Board", ALTAIS) - PROD("Falcon '040 Turbo Board", FALCON_040) +BEGIN_PROD(MACROSYSTEMS_GERMANY) + PROD("Maestro", AUDIO, MACROSYSTEMS_MAESTRO) + PROD("VLab", VIDEO, MACROSYSTEMS_VLAB) + PROD("Maestro Pro", AUDIO, MACROSYSTEMS_MAESTRO_PRO) + PROD("Retina", GFX, MACROSYSTEMS_RETINA) + PROD("MultiEvolution", SCSI, MACROSYSTEMS_MULTI_EVOLUTION) + PROD("Toccata", AUDIO, MACROSYSTEMS_TOCCATA) + PROD("Retina Z3", GFX, MACROSYSTEMS_RETINA_Z3) + PROD("VLab Motion", VIDEO, MACROSYSTEMS_VLAB_MOTION) + PROD("Altais", GFX, MACROSYSTEMS_ALTAIS) + PROD("Falcon '040", TURBO, MACROSYSTEMS_FALCON_040) END BEGIN_PROD(COMBITEC) END -BEGIN_PROD(SKI) - PROD("MAST Fireball SCSI Controller", MAST_FIREBALL) - PROD("SCSI / Dual Serial", SKI_SCSI_SERIAL) +BEGIN_PROD(SKI_PERIPHERALS) + PROD("MAST Fireball", SCSI, SKI_PERIPHERALS_MAST_FIREBALL) + PROD("SCSI/Dual Serial", SCSI_SERIAL, SKI_PERIPHERALS_SCSI_DUAL_SERIAL) +END + +BEGIN_PROD(REIS_WARE_2) + PROD("Scan King", SCANNER, REIS_WARE_SCAN_KING) END BEGIN_PROD(CAMERON) - PROD("Personal A4", PERSONAL_A4) + PROD("Personal A4", SCANNER, CAMERON_PERSONAL_A4) END BEGIN_PROD(REIS_WARE) - PROD("Handyscanner", RW_HANDYSCANNER) + PROD("Handyscanner", SCANNER, REIS_WARE_HANDYSCANNER) END +BEGIN_PROD(PHOENIX_2) + PROD("ST506", HD, PHOENIX_ST506_2) + PROD(NULL, SCSI, PHOENIX_SCSI_2) + PROD(NULL, RAM, PHOENIX_RAM_2) +END -BEGIN_MANUF - MANUF("Pacific Peripherals", PACIFIC) - MANUF("Kupke", KUPKE) - MANUF("Memphis", MEMPHIS) - MANUF("3-State", 3_STATE) - MANUF("Commodore", COMMODORE2) - MANUF("Commodore", COMMODORE) - MANUF("Commodore", COMMODORE3) - MANUF("Kolff Computer Supplies", KCS) - MANUF("Cardco", CARDCO) - MANUF("A-Squared", A_SQUARED) - MANUF("ComSpec Communications", COMSPEC) - MANUF("Anakin", ANAKIN) - MANUF("MicroBotics", MICROBOTICS) - MANUF("Access Associates", ACCESS) - MANUF("Expansion Technologies", EXPANSION_TECH) - MANUF("ASDG", ASDG) - MANUF("Imtronics", IMTRONICS) - MANUF("University of Lowell", UNIV_OF_LOWELL) - MANUF("Ameristar", AMERISTAR) - MANUF("Supra", SUPRA) - MANUF("Computer Systems Ass.", CSA) - MANUF("M-Tech", MTEC2) - MANUF("Great Valley Products", GVP3) - MANUF("ByteBox", BYTEBOX) - MANUF("Power Computing", POWER_COMPUTING) - MANUF("Great Valley Products", GVP) - MANUF("Synergy", SYNERGY) - MANUF("Xetec", XETEC) - MANUF("Progressive Peripherals", PPI) - MANUF("Xebec", XEBEC) - MANUF("Spirit", SPIRIT) - MANUF("BSC", BSC) - MANUF("BSC", BSC3) - MANUF("C Ltd.", C_LTD) - MANUF("Jochheim", JOCHHEIM) - MANUF("Checkpoint Technologies", CHECKPOINT) - MANUF("ICD", ICD) - MANUF("Kupke", KUPKE2) - MANUF("Great Valley Products", GVP4) - MANUF("Interworks Network", INTERWORKS_NET) - MANUF("Hardital Synthesis", HARDITAL) - MANUF("BSC", BSC2) - MANUF("Advanced Systems & Software", ADV_SYS_SOFT) - MANUF("Impulse", IMPULSE) - MANUF("IVS", IVS) - MANUF("Vector", VECTOR) - MANUF("XPert/ProDev", XPERT_PRODEV) - MANUF("Hydra Systems", HYDRA_SYSTEMS) - MANUF("Sunrize Industries", SUNRIZE) - MANUF("Triceratops", TRICERATOPS) - MANUF("Applied Magic", APPLIED_MAGIC) - MANUF("GFX-Base", GFX_BASE) - MANUF("RocTec", ROCTEC) - MANUF("Helfrich", HELFRICH1) - MANUF("Software Result Enterprises", SW_RESULT_ENTS) - MANUF("Masoboshi", MASOBOSHI) - MANUF("Village Tronic", VILLAGE_TRONIC) - MANUF("Utilities Unlimited", UTILITIES_ULTD) - MANUF("Amitrix", AMITRIX) - MANUF("ArMax", ARMAX) - MANUF("NewTek", NEWTEK) - MANUF("M-Tech", MTEC) - MANUF("Great Valley Products", GVP2) - MANUF("Helfrich", HELFRICH2) - MANUF("MacroSystems", MACROSYSTEMS) - MANUF("ElBox Computer", ELBOX) - MANUF("Harms Professional", HARMS_PROF) - MANUF("Micronik", MICRONIK) - MANUF("MegaMicro", MEGA_MICRO) - MANUF("Imtronics", IMTRONICS2) - MANUF("Kupke", KUPKE3) - MANUF("ITH", ITH) - MANUF("VMC", VMC) - MANUF("Information", INFORMATION) - MANUF("Vortex", VORTEX) - MANUF("DataFlyer", DATAFLYER) - MANUF("ReadySoft", READYSOFT) - MANUF("Phase5", PHASE5) - MANUF("DPS", DPS) - MANUF("Apollo", APOLLO2) - MANUF("Apollo", APOLLO) - MANUF("Petsoff LP", PETSOFF) - MANUF("Uwe Gerlach", UWE_GERLACH) - MANUF("MacroSystems", MACROSYSTEMS2) - MANUF("Combitec", COMBITEC) - MANUF("SKI Peripherals", SKI) - MANUF("Cameron", CAMERON) - MANUF("Reis-Ware", REIS_WARE) +BEGIN_PROD(COMBITEC_2) + PROD(NULL, HD, COMBITEC_HD) + PROD("SRAM", RAM, COMBITEC_SRAM) END -#define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer)) -#define NUM_GVP_PROD (sizeof(Ext_Prod_GVP)/sizeof(struct GVP_Product)) +BEGIN_PROD(HACKER) /* Unused */ +END + + +BEGIN_MANUF + MANUF("Pacific Peripherals", PACIFIC_PERIPHERALS) + MANUF("MacroSystems USA", MACROSYSTEMS_USA_2) + MANUF("Kupke", KUPKE_1) + MANUF("Memphis", MEMPHIS) + MANUF("3-State", 3_STATE) + MANUF("Commodore Braunschweig", COMMODORE_BRAUNSCHWEIG) + MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_1) + MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_2) + MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2) + MANUF("Kolff Computer Supplies", KOLFF_COMPUTER_SUPPLIES) + MANUF("Cardco Ltd.", CARDCO_1) + MANUF("A-Squared", A_SQUARED) + MANUF("Comspec Communications", COMSPEC_COMMUNICATIONS) + MANUF("Anakin Research", ANAKIN_RESEARCH) + MANUF("Microbotics", MICROBOTICS) + MANUF("Access Associates Alegra", ACCESS_ASSOCIATES_ALEGRA) + MANUF("Expansion Technologies (Pacific Cypress)", EXPANSION_TECHNOLOGIES) + MANUF("ASDG", ASDG) + MANUF("Ronin/Imtronics", IMTRONICS_1) + MANUF("Commodore/University of Lowell", CBM_UNIVERSITY_OF_LOWELL) + MANUF("Ameristar", AMERISTAR) + MANUF("Supra", SUPRA) + MANUF("Computer Systems Assosiates", COMPUTER_SYSTEMS_ASSOCIATES) + MANUF("Marc Michael Groth", MARC_MICHAEL_GROTH) + MANUF("M-Tech", M_TECH) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_1) + MANUF("ByteBox", BYTEBOX) + MANUF("DKB/Power Computing", DKB_POWER_COMPUTING) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_2) + MANUF("California Access (Synergy)", CALIFORNIA_ACCESS_SYNERGY) + MANUF("Xetec", XETEC) + MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS) + MANUF("Xebec", XEBEC) + MANUF("Spirit Technology", SPIRIT_TECHNOLOGY) + MANUF("Spirit Technology", SPIRIT_TECHNOLOGY_2) + MANUF("BSC/Alfadata", BSC_ALFADATA_1) + MANUF("BSC/Alfadata", BSC_ALFADATA_2) + MANUF("Cardco Ltd.", CARDCO_2) + MANUF("Jochheim", JOCHHEIM) + MANUF("Checkpoint Technologies", CHECKPOINT_TECHNOLOGIES) + MANUF("Edotronik", EDOTRONIK) + MANUF("NES Inc.", NES_INC) + MANUF("ICD", ICD) + MANUF("Kupke", KUPKE_2) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_3) + MANUF("Interworks Network", INTERWORKS_NETWORK) + MANUF("Hardital Synthesis", HARDITAL_SYNTHESIS) + MANUF("Applied Engineering", APPLIED_ENGINEERING) + MANUF("BSC/Alfadata", BSC_ALFADATA_3) + MANUF("Phoenix", PHOENIX) + MANUF("Advanced Storage Systems", ADVANCED_STORAGE_SYSTEMS) + MANUF("Impulse", IMPULSE) + MANUF("IVS", IVS) + MANUF("Vector", VECTOR_1) + MANUF("XPert ProDev", XPERT_PRODEV) + MANUF("Hydra Systems", HYDRA_SYSTEMS) + MANUF("Sunrize Industries", SUNRIZE_INDUSTRIES) + MANUF("Triceratops", TRICERATOPS) + MANUF("Applied Magic Inc.", APPLIED_MAGIC) + MANUF("GFX-Base", GFX_BASE) + MANUF("RocTec", ROCTEC) + MANUF("Kato", KATO) + MANUF("Atlantis", ATLANTIS) + MANUF("Protar", PROTAR) + MANUF("ACS", ACS) + MANUF("Software Results Enterprises", SOFTWARE_RESULTS_ENTERPRISES) + MANUF("Masoboshi", MASOBOSHI) + MANUF("Mainhattan-Data (A-Team)", MAINHATTAN_DATA) + MANUF("Village Tronic", VILLAGE_TRONIC) + MANUF("Utilities Unlimited", UTILITIES_UNLIMITED) + MANUF("Amitrix", AMITRIX) + MANUF("ArMax", ARMAX) + MANUF("NewTek", NEWTEK) + MANUF("M-Tech Germany", M_TECH_GERMANY) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_4) + MANUF("Apollo", APOLLO_1) + MANUF("Ingenieurbüro Helfrich", HELFRICH_2) + MANUF("MacroSystems USA", MACROSYSTEMS_USA) + MANUF("ElBox Computer", ELBOX_COMPUTER) + MANUF("Harms Professional", HARMS_PROFESSIONAL) + MANUF("Micronik", MICRONIK) + MANUF("Micronik", MICRONIK2) + MANUF("MegaMicro", MEGAMICRO) + MANUF("Ronin/Imtronics", IMTRONICS_2) + MANUF("Individual Computers", INDIVIDUAL_COMPUTERS) + MANUF("Kupke", KUPKE_3) + MANUF("ITH", ITH) + MANUF("VMC", VMC) + MANUF("Information", INFORMATION) + MANUF("Vortex", VORTEX) + MANUF("Expansion Systems", EXPANSION_SYSTEMS) + MANUF("ReadySoft", READYSOFT) + MANUF("Phase 5", PHASE5) + MANUF("DPS", DPS) + MANUF("Apollo", APOLLO_2) + MANUF("Apollo", APOLLO_3) + MANUF("Petsoff LP", PETSOFF_LP) + MANUF("Uwe Gerlach", UWE_GERLACH) + MANUF("MacroSystems Germany", MACROSYSTEMS_GERMANY) + MANUF("Combitec", COMBITEC) + MANUF("SKI Peripherals", SKI_PERIPHERALS) + MANUF("Reis-Ware", REIS_WARE_2) + MANUF("Cameron", CAMERON) + MANUF("Reis-Ware", REIS_WARE) + MANUF("Hacker Test Board", HACKER) /* Unused */ + MANUF("Phoenix", PHOENIX_2) + MANUF("Combitec", COMBITEC_2) +END + +#define NUM_MANUF (ARRAYSIZE(Manufacturers)) +#define NUM_GVP_PROD (ARRAYSIZE(Ext_Prod_GVP)) + + + /* + * Zorro product classes + * + * Make sure to keep these in sync with include/linux/zorro.h! + */ + +static const char *classnames[] = { + NULL, /* ZORRO_CLASS_UNKNOWN */ + "ArcNet Card", /* ZORRO_CLASS_ARCNET */ + "Audio Board", /* ZORRO_CLASS_AUDIO */ + "ISA Bus Bridge", /* ZORRO_CLASS_BRIDGE */ + "DSP Board", /* ZORRO_CLASS_DSP */ + "Ethernet Card", /* ZORRO_CLASS_ETHERNET */ + "Ethernet Card and Parallel Ports", /* ZORRO_CLASS_ETHERNET_PARALLEL */ + "Flash ROM", /* ZORRO_CLASS_FLASHROM */ + "FPU and RAM Expansion", /* ZORRO_CLASS_FPU_RAM */ + "Graphics Board", /* ZORRO_CLASS_GFX */ + "Graphics Board (RAM)", /* ZORRO_CLASS_GFXRAM */ + "HD Controller", /* ZORRO_CLASS_HD */ + "HD Controller and RAM Expansion", /* ZORRO_CLASS_HD_RAM */ + "IDE Interface", /* ZORRO_CLASS_IDE */ + "IDE Interface and RAM Expansion", /* ZORRO_CLASS_IDE_RAM */ + "IDE Interface and Floppy Controller", /* ZORRO_CLASS_IDE_FLOPPY */ + "ISDN Interface", /* ZORRO_CLASS_ISDN */ + "Macintosh Emulator", /* ZORRO_CLASS_MACEMU */ + "Miscellaneous Expansion Card", /* ZORRO_CLASS_MISC */ + "Modem", /* ZORRO_CLASS_MODEM */ + "Multi I/O", /* ZORRO_CLASS_MULTIIO */ + "RAM Expansion", /* ZORRO_CLASS_RAM */ + "Scanner Interface", /* ZORRO_CLASS_SCANNER */ + "SCSI Host Adapter", /* ZORRO_CLASS_SCSI */ + "SCSI Host Adapter and IDE Interface", /* ZORRO_CLASS_SCSI_IDE */ + "SCSI Host Adapter and RAM Expansion", /* ZORRO_CLASS_SCSI_RAM */ + "SCSI Host Adapter and Serial Card", /* ZORRO_CLASS_SCSI_SERIAL */ + "Multi Serial", /* ZORRO_CLASS_SERIAL */ + "Drawing Tablet Interface", /* ZORRO_CLASS_TABLET */ + "Accelerator", /* ZORRO_CLASS_TURBO */ + "Accelerator and RAM Expansion", /* ZORRO_CLASS_TURBO_RAM */ + "Accelerator and HD Controller", /* ZORRO_CLASS_TURBO_HD */ + "Accelerator and IDE Interface", /* ZORRO_CLASS_TURBO_IDE */ + "Accelerator and SCSI Host Adapter", /* ZORRO_CLASS_TURBO_SCSI */ + "Accelerator, SCSI Host Adapter and RAM Expansion", /* ZORRO_CLASS_TURBO_SCSI */ + "Video Board", /* ZORRO_CLASS_VIDEO */ +}; + +static inline const char *get_class_name(enum Zorro_Classes class) +{ + if (class < ARRAYSIZE(classnames)) + return(classnames[class]); + else + return("(**Illegal**)"); +} #endif /* CONFIG_ZORRO */ - /* - * Expansion Devices - */ + /* + * Expansion Devices + */ -int zorro_num_autocon; +u_int zorro_num_autocon; struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO]; -static u_long BoardPartFlags[ZORRO_NUM_AUTO] = { 0, }; +static u32 BoardPartFlags[ZORRO_NUM_AUTO] = { 0, }; - /* - * Find the key for the next unconfigured expansion device of a specific - * type. - * - * Part is a device specific number (0 <= part <= 31) to allow for the - * independent configuration of independent parts of an expansion board. - * Thanks to Jes Soerensen for this idea! - * - * Index is used to specify the first board in the autocon list - * to be tested. It was inserted in order to solve the problem - * with the GVP boards that uses the same product code, but - * it should help if there are other companies uses the same - * method as GVP. Drivers for boards which are not using this - * method does not need to think of this - just set index = 0. - * - * Example: - * - * while ((key = zorro_find(MY_MANUF, MY_PROD, MY_PART, 0))) { - * cd = zorro_get_board(key); - * initialise_this_board; - * zorro_config_board(key, MY_PART); - * } - */ + /* + * Find the key for the next unconfigured expansion device of a specific + * type. + * + * Part is a device specific number (0 <= part <= 31) to allow for the + * independent configuration of independent parts of an expansion board. + * Thanks to Jes Soerensen for this idea! + * + * Index is used to specify the first board in the autocon list + * to be tested. It was inserted in order to solve the problem + * with the GVP boards that uses the same product code, but + * it should help if there are other companies which use the same + * method as GVP. Drivers for boards which are not using this + * method do not need to think of this - just set index = 0. + * + * Example: + * + * while ((key = zorro_find(ZORRO_PROD_MY_BOARD, MY_PART, 0))) { + * cd = zorro_get_board(key); + * initialise_this_board; + * zorro_config_board(key, MY_PART); + * } + */ -int zorro_find(int manuf, int prod, int part, int index) +u_int zorro_find(zorro_id id, u_int part, u_int index) { - int key; - struct ConfigDev *cd; - - if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) - return(0); - - if ((part < 0) || (part > 31)) { - printk("zorro_find: bad part %d\n", part); - return(0); - } - - for (key = index + 1; key <= zorro_num_autocon; key++) { - cd = &zorro_autocon[key-1]; - if ((cd->cd_Rom.er_Manufacturer == manuf) && - (cd->cd_Rom.er_Product == prod) && - !(BoardPartFlags[key-1] & (1< 31) { + printk("zorro_find: bad part %d\n", part); + return(0); + } + + for (key = index + 1; key <= zorro_num_autocon; key++) { + cd = &zorro_autocon[key-1]; + addr = (u_long)cd->cd_BoardAddr; + if ((cd->cd_Rom.er_Manufacturer == manuf) && + (cd->cd_Rom.er_Product == prod) && + !(BoardPartFlags[key-1] & (1< zorro_num_autocon)) - printk("zorro_get_board: bad key %d\n", key); - else - cd = &zorro_autocon[key-1]; + if ((key < 1) || (key > zorro_num_autocon)) + printk("zorro_get_board: bad key %d\n", key); + else + cd = &zorro_autocon[key-1]; - return(cd); + return(cd); } - /* - * Mark a part of a board as configured - */ + /* + * Mark a part of a board as configured + */ -void zorro_config_board(int key, int part) +void zorro_config_board(u_int key, u_int part) { - if ((key < 1) || (key > zorro_num_autocon)) - printk("zorro_config_board: bad key %d\n", key); - else if ((part < 0) || (part > 31)) - printk("zorro_config_board: bad part %d\n", part); - else - BoardPartFlags[key-1] |= 1< zorro_num_autocon)) + printk("zorro_config_board: bad key %d\n", key); + else if (part > 31) + printk("zorro_config_board: bad part %d\n", part); + else if (BoardPartFlags[key-1] & (1< zorro_num_autocon)) - printk("zorro_unconfig_board: bad key %d\n", key); - else if ((part < 0) || (part > 31)) - printk("zorro_unconfig_board: bad part %d\n", part); - else - BoardPartFlags[key-1] &= ~(1< zorro_num_autocon)) + printk("zorro_unconfig_board: bad key %d\n", key); + else if (part > 31) + printk("zorro_unconfig_board: bad part %d\n", part); + else if (!(BoardPartFlags[key-1] & (1<cd_Rom.er_Manufacturer; - prod = cd->cd_Rom.er_Product; - addr = (u_long)cd->cd_BoardAddr; - size = cd->cd_BoardSize; - configured = BoardPartFlags[devnum] ? '*' : ' '; - manufname = prodname = ""; - - for (i = 0; i < NUM_MANUF; i++) - if (Manufacturers[i].ID == manuf) { - manufname = Manufacturers[i].Name; - for (j = 0; j < Manufacturers[i].NumProd; j++) - if (Manufacturers[i].Products[j].ID == prod) - if ((manuf != MANUF_GVP) || (prod != PROD_GVP)) { - prodname = Manufacturers[i].Products[j].Name; - identified = 1; - break; - } else { - /* - * The epc must be read as a short from the - * hardware. - */ - epc = *(unsigned short *)ZTWO_VADDR(addr+0x8000) & - GVP_PRODMASK; - for (k = 0; k < NUM_GVP_PROD; k++) - if (Ext_Prod_GVP[k].ID == epc) { - prodname = Ext_Prod_GVP[k].Name; - identified = 1; - break; - } - } - break; - } - - switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) { - case ERT_ZORROII: - zorro = '2'; - break; - case ERT_ZORROIII: - zorro = '3'; - break; - default: - zorro = '?'; - break; - } - if (size & 0xfffff) { - size >>= 10; - mag = 'K'; - } else { - size >>= 20; - mag = 'M'; - } - if (cd->cd_Rom.er_Type & ERTF_MEMLIST) - is_mem = " MEM"; - else - is_mem = ""; - - if (identified) - len = sprintf(buf, " %c0x%08lx: %s %s (Z%c, %ld%c%s)\n", configured, addr, - manufname, prodname, zorro, size, mag, is_mem); - else if (manuf == MANUF_HACKER) - len = sprintf(buf, " 0x%08lx: Hacker Test Board 0x%02x (Z%c, %ld%c%s)\n", - addr, prod, zorro, size, mag, is_mem); - else { - len = sprintf(buf, " 0x%08lx: [%04x:%02x] made by %s (Z%c, %ld%c%s)\n", - addr, manuf, prod, manufname, zorro, size, mag, is_mem); - len += sprintf(buf+len, " Please report this unknown device to " - "Geert.Uytterhoeven@cs.kuleuven.ac.be\n"); - } - return(len); + const struct ConfigDev *cd = &zorro_autocon[devnum]; + u32 configured = BoardPartFlags[devnum]; + u_int manuf = cd->cd_Rom.er_Manufacturer; + u_int prod = cd->cd_Rom.er_Product; + u_int class = ZORRO_CLASS_UNKNOWN; + u_int epc = 0; + const char *manufname = "Unknown"; + const char *prodname = "Unknown"; + const char *classname; + u_int i, j, k, len = 0; + u_long addr = (u_long)cd->cd_BoardAddr; + u_long size = cd->cd_BoardSize; + char mag; + int identified = 0, gvp = 0; + + if (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) || + prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE)) { + for (i = 0; i < NUM_MANUF; i++) + if (Manufacturers[i].Manuf == manuf) { + manufname = Manufacturers[i].Name; + for (j = 0; j < Manufacturers[i].NumProd; j++) + if (Manufacturers[i].Products[j].Prod == prod) { + prodname = Manufacturers[i].Products[j].Name; + class = Manufacturers[i].Products[j].Class; + identified = 1; + break; + } + } + /* Put workarounds for ID clashes here */ + if (manuf == ZORRO_MANUF(ZORRO_PROD_HELFRICH_RAINBOW_III) && + prod == ZORRO_PROD(ZORRO_PROD_HELFRICH_RAINBOW_III)) + manufname = "Ingenieurbüro Helfrich"; + } else { + manufname = "Great Valley Products"; + gvp = 1; + epc = *(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK; + for (k = 0; k < NUM_GVP_PROD; k++) + if (epc == Ext_Prod_GVP[k].EPC) { + prodname = Ext_Prod_GVP[k].Name; + class = Ext_Prod_GVP[k].Class; + identified = 1; + break; + } + } + classname = get_class_name(class); + if (size & 0xfffff) { + size >>= 10; + mag = 'K'; + } else { + size >>= 20; + mag = 'M'; + } + if (verbose) { + const char *zorro; + int is_mem = cd->cd_Rom.er_Type & ERTF_MEMLIST; + switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) { + case ERT_ZORROII: + zorro = "Zorro II"; + break; + case ERT_ZORROIII: + zorro = "Zorro III"; + break; + default: + zorro = "Unknown Zorro"; + break; + } + if (!prodname) + prodname = "Unknown"; + if (!classname) + classname = "Unknown"; + len = sprintf(buf, " Device %d at 0x%08lx: ID=%04x:%02x", devnum, + addr, manuf, prod); + if (gvp) + len += sprintf(buf+len, ":%02x", epc); + len += sprintf(buf+len, ", %s, %ld%c", zorro, size, mag); + if (is_mem) + len += sprintf(buf+len, ", System RAM"); + else + len += sprintf(buf+len, ", Configured=%08x", configured); + len += sprintf(buf+len, "\n" + " Manufacturer: %s\n" + " Product Name: %s\n" + " Board Class : %s\n", + manufname, prodname, classname); + } else { + len = sprintf(buf, " %c%08lx: ", configured ? '*' : ' ', addr); + if (identified) { + len += sprintf(buf+len, "%s", manufname); + if (prodname) + len += sprintf(buf+len, " %s", prodname); + if (classname) + len += sprintf(buf+len, " %s", classname); + } else if (manuf == ZORRO_MANUF_HACKER) + len += sprintf(buf+len, "Hacker Test Board %02x", prod); + else if (gvp) + len += sprintf(buf+len, "[%04x:%02x:%02x] made by %s", manuf, prod, + epc, manufname); + else + len += sprintf(buf+len, "[%04x:%02x] made by %s", manuf, prod, + manufname); + len += sprintf(buf+len, " (%ld%c)\n", size, mag); + if (!identified && manuf != ZORRO_MANUF_HACKER) + len += sprintf(buf+len, " Please report this unknown device to " + "zorro@linux-m68k.org\n"); + } + return(len); } - /* - * Identify all known AutoConfig Expansion Devices - */ + /* + * Identify all known AutoConfig Expansion Devices + */ void zorro_identify(void) { - int i; - char tmp[160]; + u_int i; + char tmp[256]; - if (!AMIGAHW_PRESENT(ZORRO)) - return; + if (!AMIGAHW_PRESENT(ZORRO)) + return; - printk("Probing AutoConfig expansion device(s):\n"); - for (i = 0; i < zorro_num_autocon; i++) { - identify(i, tmp); - printk(tmp); - } - if (!zorro_num_autocon) - printk("No AutoConfig expansion devices present.\n"); + printk("Probing AutoConfig expansion device(s):\n"); + for (i = 0; i < zorro_num_autocon; i++) { + identify(i, tmp, 0); + printk(tmp); + } + if (!zorro_num_autocon) + printk("No AutoConfig expansion devices present.\n"); } - /* - * Get the list of all AutoConfig Expansion Devices - */ + /* + * Get the list of all AutoConfig Expansion Devices + */ int zorro_get_list(char *buffer) { - int i, j, len = 0; - char tmp[160]; + u_int i, len = 0, len2; + char tmp[256]; - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { - len = sprintf(buffer, "AutoConfig expansion devices:\n"); - for (i = 0; i < zorro_num_autocon; i++) { - j = identify(i, tmp); - if (len+j >= 4075) { - len += sprintf(buffer+len, "4K limit reached!\n"); - break; - } - strcpy(buffer+len, tmp); - len += j; - } - } - return(len); + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { + len = sprintf(buffer, "AutoConfig expansion devices:\n"); + for (i = 0; i < zorro_num_autocon; i++) { + len2 = identify(i, tmp, 1); + if (len+len2 >= 4075) { + len += sprintf(buffer+len, "4K limit reached!\n"); + break; + } + strcpy(buffer+len, tmp); + len += len2; + } + } + return(len); } #endif /* CONFIG_ZORRO */ - /* - * Bitmask indicating portions of available Zorro II RAM that are unused - * by the system. Every bit represents a 64K chunk, for a maximum of 8MB - * (128 chunks, physical 0x00200000-0x009fffff). - * - * If you want to use (= allocate) portions of this RAM, you should clear - * the corresponding bits. - * - * Possible uses: - * - z2ram device - * - SCSI DMA bounce buffers - */ + /* + * Bitmask indicating portions of available Zorro II RAM that are unused + * by the system. Every bit represents a 64K chunk, for a maximum of 8MB + * (128 chunks, physical 0x00200000-0x009fffff). + * + * If you want to use (= allocate) portions of this RAM, you should clear + * the corresponding bits. + * + * Possible uses: + * - z2ram device + * - SCSI DMA bounce buffers + */ -u_long zorro_unused_z2ram[4] = { 0, 0, 0, 0 }; +u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 }; static void mark_region(u_long addr, u_long size, int flag) { - u_long start, end, chunk; + u_long start, end, chunk; - if (flag) { - start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; - end = (addr+size) & ~Z2RAM_CHUNKMASK; - } else { - start = addr & ~Z2RAM_CHUNKMASK; - end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; - } - if (end <= Z2RAM_START || start >= Z2RAM_END) - return; - start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START; - end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; - while (start < end) { - chunk = start>>Z2RAM_CHUNKSHIFT; - if (flag) - set_bit( chunk, zorro_unused_z2ram ); - else - clear_bit( chunk, zorro_unused_z2ram ); - start += Z2RAM_CHUNKSIZE; - } + if (flag) { + start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; + end = (addr+size) & ~Z2RAM_CHUNKMASK; + } else { + start = addr & ~Z2RAM_CHUNKMASK; + end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; + } + if (end <= Z2RAM_START || start >= Z2RAM_END) + return; + start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START; + end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; + while (start < end) { + chunk = start>>Z2RAM_CHUNKSHIFT; + if (flag) + set_bit( chunk, zorro_unused_z2ram ); + else + clear_bit( chunk, zorro_unused_z2ram ); + start += Z2RAM_CHUNKSIZE; + } } - /* - * Initialization - */ + /* + * Initialization + */ -__initfunc(void zorro_init(void)) +void zorro_init(void) { - int i; - struct ConfigDev *cd; + u_int i; + const struct ConfigDev *cd; - if (!AMIGAHW_PRESENT(ZORRO)) - return; + if (!AMIGAHW_PRESENT(ZORRO)) + return; - /* Mark all available Zorro II memory */ - for (i = 0; i < zorro_num_autocon; i++) { - cd = &zorro_autocon[i]; - if (cd->cd_Rom.er_Type & ERTF_MEMLIST) - mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1); - } - /* Unmark all used Zorro II memory */ - for (i = 0; i < m68k_num_memory; i++) - mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0); + /* Mark all available Zorro II memory */ + for (i = 0; i < zorro_num_autocon; i++) { + cd = &zorro_autocon[i]; + if (cd->cd_Rom.er_Type & ERTF_MEMLIST) + mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1); + } + + /* Unmark all used Zorro II memory */ + for (i = 0; i < m68k_num_memory; i++) + mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0); } diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/Makefile linux/arch/m68k/apollo/Makefile --- v2.1.86/linux/arch/m68k/apollo/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/apollo/Makefile Thu Feb 12 16:30:12 1998 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/amiga 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... + +O_TARGET := apollo.o +O_OBJS := config.o dn_ints.o \ + + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/config.c linux/arch/m68k/apollo/config.c --- v2.1.86/linux/arch/m68k/apollo/config.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/apollo/config.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern struct consw fb_con; +extern void dn_sched_init(void (*handler)(int,void *,struct pt_regs *)); +extern int dn_keyb_init(void); +extern int dn_dummy_kbdrate(struct kbd_repeat *); +extern void dn_init_IRQ(void); +#if 0 +extern void (*dn_default_handler[])(int,void *,struct pt_regs *); +#endif +extern int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); +extern void dn_free_irq(unsigned int irq, void *dev_id); +extern void dn_enable_irq(unsigned int); +extern void dn_disable_irq(unsigned int); +extern int dn_get_irq_list(char *); +extern unsigned long dn_gettimeoffset(void); +extern void dn_gettod(int *, int *, int *, int *, int *, int *); +extern int dn_dummy_hwclk(int, struct hwclk_time *); +extern int dn_dummy_set_clock_mmss(unsigned long); +extern void dn_mksound(unsigned int count, unsigned int ticks); +extern void dn_dummy_reset(void); +extern void dn_dummy_waitbut(void); +extern struct fb_info *dn_fb_init(long *); +extern void dn_dummy_debug_init(void); +extern void (*kd_mksound)(unsigned int, unsigned int); +extern void dn_dummy_video_setup(char *,int *); +extern void dn_process_int(int irq, struct pt_regs *fp); + +static struct console dn_console_driver; +static void dn_debug_init(void); +static void dn_timer_int(int irq,void *, struct pt_regs *); +static void (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL; + +int dn_serial_console_wait_key(void) { + + while(!(sio01.srb_csrb & 1)) + barrier(); + return sio01.rhrb_thrb; +} + +void dn_serial_console_write (const char *str,unsigned int count) +{ + while(count--) { + if (*str == '\n') { + sio01.rhrb_thrb = (unsigned char)'\r'; + while (!(sio01.srb_csrb & 0x4)) + ; + } + sio01.rhrb_thrb = (unsigned char)*str++; + while (!(sio01.srb_csrb & 0x4)) + ; + } +} + +void dn_serial_print (const char *str) +{ + while (*str) { + if (*str == '\n') { + sio01.rhrb_thrb = (unsigned char)'\r'; + while (!(sio01.srb_csrb & 0x4)) + ; + } + sio01.rhrb_thrb = (unsigned char)*str++; + while (!(sio01.srb_csrb & 0x4)) + ; + } +} + +void config_apollo(void) { + + dn_serial_print("Config apollo !\n"); +#if 0 + dn_debug_init(); +#endif + printk("Config apollo !\n"); + + + mach_sched_init=dn_sched_init; /* */ + mach_keyb_init=dn_keyb_init; + mach_kbdrate=dn_dummy_kbdrate; + mach_init_IRQ=dn_init_IRQ; + mach_default_handler=NULL; + mach_request_irq = dn_request_irq; + mach_free_irq = dn_free_irq; + enable_irq = dn_enable_irq; + disable_irq = dn_disable_irq; + mach_get_irq_list = dn_get_irq_list; + mach_gettimeoffset = dn_gettimeoffset; + mach_gettod = dn_gettod; /* */ + mach_max_dma_address = 0xffffffff; + mach_hwclk = dn_dummy_hwclk; /* */ + mach_set_clock_mmss = dn_dummy_set_clock_mmss; /* */ + mach_process_int = dn_process_int; +#ifdef CONFIG_BLK_DEV_FD + mach_floppy_init = dn_dummy_floppy_init; + mach_floppy_setup = dn_dummy_floppy_setup; +#endif + mach_reset = dn_dummy_reset; /* */ + conswitchp = &fb_con; +#if 0 + mach_fb_init = dn_fb_init; + mach_video_setup = dn_dummy_video_setup; +#endif + kd_mksound = dn_mksound; + +} + +void dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) { + + volatile unsigned char x; + + sched_timer_handler(irq,dev_id,fp); + + x=*(volatile unsigned char *)(IO_BASE+0x10803); + x=*(volatile unsigned char *)(IO_BASE+0x10805); + +} + +void dn_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) { + + dn_serial_print("dn sched_init\n"); + +#if 0 + /* program timer 2 */ + *(volatile unsigned char *)(IO_BASE+0x10803)=0x00; + *(volatile unsigned char *)(IO_BASE+0x10809)=0; + *(volatile unsigned char *)(IO_BASE+0x1080b)=50; + + /* program timer 3 */ + *(volatile unsigned char *)(IO_BASE+0x10801)=0x00; + *(volatile unsigned char *)(IO_BASE+0x1080c)=0; + *(volatile unsigned char *)(IO_BASE+0x1080f)=50; +#endif + /* program timer 1 */ + *(volatile unsigned char *)(IO_BASE+0x10803)=0x01; + *(volatile unsigned char *)(IO_BASE+0x10801)=0x40; + *(volatile unsigned char *)(IO_BASE+0x10805)=0x09; + *(volatile unsigned char *)(IO_BASE+0x10807)=0xc4; + + /* enable IRQ of PIC B */ + *(volatile unsigned char *)(IO_BASE+PICA+1)&=(~8); + + + + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803)); + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803)); + + sched_timer_handler=timer_routine; + request_irq(0,dn_timer_int,0,NULL,NULL); + + +} + +unsigned long dn_gettimeoffset(void) { + + return 0xdeadbeef; + +} + +void dn_gettod(int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { + + *yearp=rtc->year; + *monp=rtc->month; + *dayp=rtc->day_of_month; + *hourp=rtc->hours; + *minp=rtc->minute; + *secp=rtc->second; + +printk("gettod: %d %d %d %d %d %d\n",*yearp,*monp,*dayp,*hourp,*minp,*secp); + +} + +int dn_dummy_hwclk(int op, struct hwclk_time *t) { + + dn_serial_print("hwclk !\n"); + + if(!op) { /* read */ + t->sec=rtc->second; + t->min=rtc->minute; + t->hour=rtc->hours; + t->day=rtc->day_of_month; + t->wday=rtc->day_of_week; + t->mon=rtc->month; + t->year=rtc->year; + } else { + rtc->second=t->sec; + rtc->minute=t->min; + rtc->hours=t->hour; + rtc->day_of_month=t->day; + if(t->wday!=-1) + rtc->day_of_week=t->wday; + rtc->month=t->mon; + rtc->year=t->year; + } + + dn_serial_print("hwclk end!\n"); + return 0; + +} + +int dn_dummy_set_clock_mmss(unsigned long nowtime) { + + printk("set_clock_mmss\n"); + + return 0; + +} + +void dn_dummy_reset(void) { + + dn_serial_print("The end !\n"); + + for(;;); + +} + +void dn_dummy_waitbut(void) { + + dn_serial_print("waitbut\n"); + +} + +#if 0 +void dn_debug_init(void) { + + dn_console_driver.write=dn_serial_console_write; + register_console(&dn_console_driver); + +} +#endif diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/dn_debug.c linux/arch/m68k/apollo/dn_debug.c --- v2.1.86/linux/arch/m68k/apollo/dn_debug.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/apollo/dn_debug.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,23 @@ +#include + +#define DN_DEBUG_BUFFER_BASE 0x82800000 +#define DN_DEBUG_BUFFER_SIZE 8*1024*1024 + +static char *current_dbg_ptr=DN_DEBUG_BUFFER_BASE; + +int dn_deb_printf(const char *fmt, ...) { + + va_list args; + int i; + + if(current_dbg_ptr<(DN_DEBUG_BUFFER_BASE + DN_DEBUG_BUFFER_SIZE)) { + va_start(args,fmt); + i=vsprintf(current_dbg_ptr,fmt,args); + va_end(args); + current_dbg_ptr+=i; + + return i; + } + else + return 0; +} diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/dn_ints.c linux/arch/m68k/apollo/dn_ints.c --- v2.1.86/linux/arch/m68k/apollo/dn_ints.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/apollo/dn_ints.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static irq_handler_t dn_irqs[16]; + +extern void write_keyb_cmd(u_short length, u_char *cmd); +static char BellOnCommand[] = { 0xFF, 0x21, 0x81 }, + BellOffCommand[] = { 0xFF, 0x21, 0x82 }; + +void dn_process_int(int irq, struct pt_regs *fp) { + +#if 0 + unsigned char x; +#endif + +#if 0 + printk("Aha DN interrupt ! : %d\n",irq); +#endif + + if(dn_irqs[irq-160].handler) { + dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp); + } + else { + printk("spurious irq %d occured\n",irq); + } + +#if 0 + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803)); + x=*(volatile unsigned char *)(IO_BASE+0x10805); +#endif + + *(volatile unsigned char *)(IO_BASE+0x11000)=0x20; + *(volatile unsigned char *)(IO_BASE+0x11100)=0x20; + +} + +void dn_init_IRQ(void) { + + int i; + + printk("Init IRQ\n"); + + for(i=0;i<16;i++) { + dn_irqs[i].handler=NULL; + dn_irqs[i].flags=IRQ_FLG_STD; + dn_irqs[i].dev_id=NULL; + dn_irqs[i].devname=NULL; + } + +} + +int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { + + printk("dn request IRQ\n"); + + if((irq<0) || (irq>15)) { + printk("Trying to request illegal IRQ\n"); + return -ENXIO; + } + + if(!dn_irqs[irq].handler) { + dn_irqs[irq].handler=handler; + dn_irqs[irq].flags=IRQ_FLG_STD; + dn_irqs[irq].dev_id=dev_id; + dn_irqs[irq].devname=devname; + if(irq<8) + *(volatile unsigned char *)(IO_BASE+PICA+1)&=~(1<15)) { + printk("Trying to free illegal IRQ\n"); + return ; + } + + if(irq<8) + *(volatile unsigned char *)(IO_BASE+PICA+1)|=(1< IRQ_TYPE_PRIO) { printk ("%s: Bad irq type %ld requested from %s\n", __FUNCTION__, flags, devname); @@ -600,11 +612,11 @@ continue; if (i < STMFP_SOURCE_BASE) len += sprintf(buf+len, "auto %2d: %10u ", - i, kstat.interrupts[i]); + i, kstat.irqs[0][i]); else len += sprintf(buf+len, "vec $%02x: %10u ", IRQ_SOURCE_TO_VECTOR(i), - kstat.interrupts[i]); + kstat.irqs[0][i]); if (irq_handler[i].handler != atari_call_irq_list) { len += sprintf(buf+len, "%s\n", irq_param[i].devname); diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c --- v2.1.86/linux/arch/m68k/atari/atakeyb.c Mon Jul 7 08:18:53 1997 +++ linux/arch/m68k/atari/atakeyb.c Thu Feb 12 16:30:12 1998 @@ -32,7 +32,6 @@ #include #include -extern int ovsc_switchmode; extern unsigned char mach_keyboard_type; static void atakeyb_rep( unsigned long ignore ); extern unsigned int keymap_count; @@ -504,23 +503,6 @@ } } -#ifdef KEYB_WRITE_INTERRUPT - if (acia_stat & ACIA_TDRE) /* transmit of character is finished */ - { - if (kb_state.buf) - { - acia.key_data = *kb_state.buf++; - kb_state.len--; - if (kb_state.len == 0) - { - kb_state.buf = NULL; - if (!kb_state.kernel_mode) - /* unblock something */; - } - } - } -#endif - #if 0 if (acia_stat & ACIA_CTS) /* cannot happen */; @@ -537,26 +519,6 @@ goto repeat; } -#ifdef KEYB_WRITE_INTERRUPT -void ikbd_write(const char *str, int len) -{ - u_char acia_stat; - - if (kb_stat.buf) - /* wait */; - acia_stat = acia.key_ctrl; - if (acia_stat & ACIA_TDRE) - { - if (len != 1) - { - kb_stat.buf = str + 1; - kb_stat.len = len - 1; - } - acia.key_data = *str; - /* poll */ - } -} -#else /* * I write to the keyboard without using interrupts, I poll instead. * This takes for the maximum length string allowed (7) at 7812.5 baud @@ -581,7 +543,6 @@ } } } -#endif /* Reset (without touching the clock) */ void ikbd_reset(void) @@ -828,33 +789,28 @@ atari_turnoff_irq(IRQ_MFP_ACIA); do { - acia.key_ctrl = ACIA_RESET; /* reset ACIA */ + /* reset IKBD ACIA */ + acia.key_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; (void)acia.key_ctrl; (void)acia.key_data; - acia.mid_ctrl = ACIA_RESET; /* reset other ACIA */ + /* reset MIDI ACIA */ + acia.mid_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; (void)acia.mid_ctrl; (void)acia.mid_data; /* divide 500kHz by 64 gives 7812.5 baud */ /* 8 data no parity 1 start 1 stop bit */ /* receive interrupt enabled */ -#ifdef KEYB_WRITE_INTERRUPT - /* RTS low, transmit interrupt enabled */ - if (ovsc_switchmode == 1) - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTIE|ACIA_RIE); - /* switch on OverScan via keyboard ACIA */ - else - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTIE|ACIA_RIE); -#else - /* RTS low, transmit interrupt disabled */ - if (ovsc_switchmode == 1) - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE); - else - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTID|ACIA_RIE); -#endif + /* RTS low (except if switch selected), transmit interrupt disabled */ + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | + ((atari_switches & ATARI_SWITCH_IKBD) ? + ACIA_RHTID : ACIA_RLTID); - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S; + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; } /* make sure the interrupt line is up */ while ((mfp.par_dt_reg & 0x10) == 0); diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/atari_ksyms.c linux/arch/m68k/atari/atari_ksyms.c --- v2.1.86/linux/arch/m68k/atari/atari_ksyms.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/atari/atari_ksyms.c Thu Feb 12 16:30:12 1998 @@ -7,24 +7,32 @@ #include #include #include +#include extern void atari_microwire_cmd( int cmd ); +extern int atari_MFP_init_done; +extern int atari_SCC_init_done; extern int atari_SCC_reset_done; EXPORT_SYMBOL(atari_mch_cookie); +EXPORT_SYMBOL(atari_mch_type); EXPORT_SYMBOL(atari_hw_present); -EXPORT_SYMBOL(is_medusa); -EXPORT_SYMBOL(is_hades); +EXPORT_SYMBOL(atari_switches); +EXPORT_SYMBOL(atari_dont_touch_floppy_select); EXPORT_SYMBOL(atari_register_vme_int); EXPORT_SYMBOL(atari_unregister_vme_int); EXPORT_SYMBOL(stdma_lock); EXPORT_SYMBOL(stdma_release); EXPORT_SYMBOL(stdma_others_waiting); EXPORT_SYMBOL(stdma_islocked); +EXPORT_SYMBOL(atari_stram_alloc); +EXPORT_SYMBOL(atari_stram_free); EXPORT_SYMBOL(atari_mouse_buttons); EXPORT_SYMBOL(atari_mouse_interrupt_hook); EXPORT_SYMBOL(atari_MIDI_interrupt_hook); +EXPORT_SYMBOL(atari_MFP_init_done); +EXPORT_SYMBOL(atari_SCC_init_done); EXPORT_SYMBOL(atari_SCC_reset_done); EXPORT_SYMBOL(ikbd_write); EXPORT_SYMBOL(ikbd_mouse_y0_top); diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c --- v2.1.86/linux/arch/m68k/atari/atasound.c Fri Dec 20 01:19:58 1996 +++ linux/arch/m68k/atari/atasound.c Thu Feb 12 16:30:12 1998 @@ -1,17 +1,16 @@ /* -linux/arch/m68k/atari/atasound.c - -++Geert: Moved almost all stuff to linux/drivers/sound/ - -The author of atari_nosound, atari_mksound and atari_microwire_cmd is -unknown. -(++roman: That's me... :-) - -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. - -*/ + * linux/arch/m68k/atari/atasound.c + * + * ++Geert: Moved almost all stuff to linux/drivers/sound/ + * + * The author of atari_nosound, atari_mksound and atari_microwire_cmd is + * unknown. (++roman: That's me... :-) + * + * 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 diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c --- v2.1.86/linux/arch/m68k/atari/config.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/atari/config.c Thu Feb 12 16:30:12 1998 @@ -27,35 +27,33 @@ #include #include #include -#include -#include -#include #include -#include #include +#include #include #include #include -#include #include - +#include #include -#include -#include -#include #include -#ifdef CONFIG_KGDB -#include -#endif - u_long atari_mch_cookie; +u_long atari_mch_type = 0; struct atari_hw_present atari_hw_present; +u_long atari_switches = 0; +int atari_dont_touch_floppy_select = 0; +int atari_rtc_year_offset; -extern char m68k_debug_device[]; +/* local function prototypes */ +static void atari_reset( void ); +#ifdef CONFIG_ATARI_FLOPPY +extern void atari_floppy_setup(char *, int *); +#endif +static void atari_get_model(char *model); +static int atari_get_hardware_list(char *buffer); -static void atari_sched_init(void (*)(int, void *, struct pt_regs *)); /* atari specific keyboard functions */ extern int atari_keyb_init(void); extern int atari_kbdrate (struct kbd_repeat *); @@ -68,33 +66,36 @@ extern void atari_enable_irq (unsigned int); extern void atari_disable_irq (unsigned int); extern int atari_get_irq_list (char *buf); -static void atari_get_model(char *model); -static int atari_get_hardware_list(char *buffer); -/* atari specific timer functions */ -static unsigned long atari_gettimeoffset (void); -static void atari_mste_gettod (int *, int *, int *, int *, int *, int *); -static void atari_gettod (int *, int *, int *, int *, int *, int *); -static int atari_mste_hwclk (int, struct hwclk_time *); -static int atari_hwclk (int, struct hwclk_time *); -static int atari_mste_set_clock_mmss (unsigned long); -static int atari_set_clock_mmss (unsigned long); extern void atari_mksound( unsigned int count, unsigned int ticks ); -static void atari_reset( void ); -#ifdef CONFIG_BLK_DEV_FD -extern int atari_floppy_init (void); -extern void atari_floppy_setup(char *, int *); +#ifdef CONFIG_HEARTBEAT +static void atari_heartbeat( int on ); #endif extern struct consw fb_con; -extern struct fb_info *atari_fb_init(long *); -static void atari_debug_init(void); -extern void atari_video_setup(char *, int *); - -static struct console atari_console_driver; - -/* Can be set somewhere, if a SCC master reset has already be done and should - * not be repeated; used by kgdb */ -int atari_SCC_reset_done = 0; +/* atari specific timer functions (in time.c) */ +extern void atari_sched_init(void (*)(int, void *, struct pt_regs *)); +extern unsigned long atari_gettimeoffset (void); +extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *); +extern void atari_tt_gettod (int *, int *, int *, int *, int *, int *); +extern int atari_mste_hwclk (int, struct hwclk_time *); +extern int atari_tt_hwclk (int, struct hwclk_time *); +extern int atari_mste_set_clock_mmss (unsigned long); +extern int atari_tt_set_clock_mmss (unsigned long); + +/* atari specific debug functions (in debug.c) */ +extern void atari_debug_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +static char atari_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */ + "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\000\000\000()/*789456123" /* 0x60 - 0x6f */ + "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif extern void (*kd_mksound)(unsigned int, unsigned int); @@ -237,18 +238,62 @@ case BI_ATARI_MCH_COOKIE: atari_mch_cookie = *data; break; + case BI_ATARI_MCH_TYPE: + atari_mch_type = *data; + break; default: unknown = 1; } return(unknown); } + +/* Parse the Atari-specific switches= option. */ +__initfunc(void atari_switches_setup( const char *str, unsigned len )) +{ + char switches[len+1]; + char *p; + int ovsc_shift; + + /* copy string to local array, strtok works destructively... */ + strncpy( switches, str, len ); + switches[len] = 0; + atari_switches = 0; + + /* parse the options */ + for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) { + ovsc_shift = 0; + if (strncmp( p, "ov_", 3 ) == 0) { + p += 3; + ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; + } + + if (strcmp( p, "ikbd" ) == 0) { + /* RTS line of IKBD ACIA */ + atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; + } + else if (strcmp( p, "midi" ) == 0) { + /* RTS line of MIDI ACIA */ + atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; + } + else if (strcmp( p, "snd6" ) == 0) { + atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; + } + else if (strcmp( p, "snd7" ) == 0) { + atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; + } + } +} + + /* * Setup the Atari configuration info */ __initfunc(void config_atari(void)) { + unsigned short tos_version; + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); atari_debug_init(); @@ -267,22 +312,40 @@ mach_get_irq_list = atari_get_irq_list; mach_gettimeoffset = atari_gettimeoffset; mach_reset = atari_reset; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_init = atari_floppy_init; +#ifdef CONFIG_ATARI_FLOPPY mach_floppy_setup = atari_floppy_setup; #endif conswitchp = &fb_con; - mach_fb_init = atari_fb_init; mach_max_dma_address = 0xffffff; - mach_video_setup = atari_video_setup; kd_mksound = atari_mksound; +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 98; /* HELP */ + mach_sysrq_shift_state = 8; /* Alt */ + mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ + mach_sysrq_xlate = atari_sysrq_xlate; +#endif +#ifdef CONFIG_HEARTBEAT + mach_heartbeat = atari_heartbeat; +#endif + /* Set switches as requested by the user */ + if (atari_switches & ATARI_SWITCH_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & ATARI_SWITCH_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | + ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); + } + /* ++bjoern: * Determine hardware present */ printk( "Atari hardware found: " ); - if (is_medusa || is_hades) { + if (MACH_IS_MEDUSA || MACH_IS_HADES) { /* There's no Atari video hardware on the Medusa, but all the * addresses below generate a DTACK so no bus error occurs! */ } @@ -324,12 +387,12 @@ ATARIHW_SET(SCSI_DMA); printk( "TT_SCSI_DMA " ); } - if (!is_hades && hwreg_present( &st_dma.dma_hi )) { + if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { ATARIHW_SET(STND_DMA); printk( "STND_DMA " ); } - if (is_medusa || /* The ST-DMA address registers aren't readable - * on all Medusas, so the test below may fail */ + if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable + * on all Medusas, so the test below may fail */ (hwreg_present( &st_dma.dma_vhi ) && (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && @@ -346,11 +409,12 @@ ATARIHW_SET(YM_2149); printk( "YM2149 " ); } - if (!is_medusa && !is_hades && hwreg_present( &tt_dmasnd.ctrl )) { + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present( &tt_dmasnd.ctrl )) { ATARIHW_SET(PCM_8BIT); printk( "PCM " ); } - if (!is_hades && hwreg_present( &codec.unused5 )) { + if (!MACH_IS_HADES && hwreg_present( &codec.unused5 )) { ATARIHW_SET(CODEC); printk( "CODEC " ); } @@ -364,7 +428,7 @@ (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) #else - !is_medusa && !is_hades + !MACH_IS_MEDUSA && !MACH_IS_HADES #endif ) { ATARIHW_SET(SCC_DMA); @@ -378,7 +442,7 @@ ATARIHW_SET( ST_ESCC ); printk( "ST_ESCC " ); } - if (is_hades) + if (MACH_IS_HADES) { ATARIHW_SET( VME ); printk( "VME " ); @@ -393,20 +457,22 @@ ATARIHW_SET(ANALOG_JOY); printk( "ANALOG_JOY " ); } - if (!is_hades && hwreg_present( blitter.halftone )) { + if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { ATARIHW_SET(BLITTER); printk( "BLITTER " ); } - if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) { + if (hwreg_present((void *)0xfff00039)) { ATARIHW_SET(IDE); printk( "IDE " ); } #if 1 /* This maybe wrong */ - if (!is_medusa && !is_hades && + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && hwreg_present( &tt_microwire.data ) && hwreg_present( &tt_microwire.mask ) && (tt_microwire.mask = 0x7ff, + udelay(1), tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, + udelay(1), tt_microwire.data != 0)) { ATARIHW_SET(MICROWIRE); while (tt_microwire.mask != 0x7ff) ; @@ -416,24 +482,24 @@ if (hwreg_present( &tt_rtc.regsel )) { ATARIHW_SET(TT_CLK); printk( "TT_CLK " ); - mach_gettod = atari_gettod; - mach_hwclk = atari_hwclk; - mach_set_clock_mmss = atari_set_clock_mmss; + mach_gettod = atari_tt_gettod; + mach_hwclk = atari_tt_hwclk; + mach_set_clock_mmss = atari_tt_set_clock_mmss; } - if (!is_hades && hwreg_present( &mste_rtc.sec_ones)) { + if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { ATARIHW_SET(MSTE_CLK); printk( "MSTE_CLK "); mach_gettod = atari_mste_gettod; mach_hwclk = atari_mste_hwclk; mach_set_clock_mmss = atari_mste_set_clock_mmss; } - if (!is_medusa && !is_hades && + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && hwreg_present( &dma_wd.fdc_speed ) && hwreg_write( &dma_wd.fdc_speed, 0 )) { ATARIHW_SET(FDCSPEED); printk( "FDC_SPEED "); } - if (!is_hades && !ATARIHW_PRESENT(ST_SCSI)) { + if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { ATARIHW_SET(ACSI); printk( "ACSI " ); } @@ -491,153 +557,24 @@ : "d0" ); } -} - -__initfunc(static void -atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) -{ - /* set Timer C data Register */ - mfp.tim_dt_c = INT_TICKS; - /* start timer C, div = 1:100 */ - mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; - /* install interrupt service routine for MFP Timer C */ - request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, - "timer", timer_routine); -} - -/* ++andreas: gettimeoffset fixed to check for pending interrupt */ - -#define TICK_SIZE 10000 - -/* This is always executed with interrupts disabled. */ -static unsigned long atari_gettimeoffset (void) -{ - unsigned long ticks, offset = 0; - /* read MFP timer C current value */ - ticks = mfp.tim_dt_c; - /* The probability of underflow is less than 2% */ - if (ticks > INT_TICKS - INT_TICKS / 50) - /* Check for pending timer interrupt */ - if (mfp.int_pn_b & (1 << 5)) - offset = TICK_SIZE; - - ticks = INT_TICKS - ticks; - ticks = ticks * 10000L / INT_TICKS; - - return ticks + offset; -} - - -static void -mste_read(struct MSTE_RTC *val) -{ -#define COPY(v) val->v=(mste_rtc.v & 0xf) - do { - COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; - COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; - COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; - COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; - COPY(year_tens) ; - /* prevent from reading the clock while it changed */ - } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); -#undef COPY -} - -static void -mste_write(struct MSTE_RTC *val) -{ -#define COPY(v) mste_rtc.v=val->v - do { - COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; - COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; - COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; - COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; - COPY(year_tens) ; - /* prevent from writing the clock while it changed */ - } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); -#undef COPY -} - -#define RTC_READ(reg) \ - ({ unsigned char __val; \ - outb(reg,&tt_rtc.regsel); \ - __val = tt_rtc.data; \ - __val; \ - }) - -#define RTC_WRITE(reg,val) \ - do { \ - outb(reg,&tt_rtc.regsel); \ - tt_rtc.data = (val); \ - } while(0) - - -static void atari_mste_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - int hr24=0, hour; - struct MSTE_RTC val; - - mste_rtc.mode=(mste_rtc.mode | 1); - hr24=mste_rtc.mon_tens & 1; - mste_rtc.mode=(mste_rtc.mode & ~1); - - mste_read(&val); - *secp = val.sec_ones + val.sec_tens * 10; - *minp = val.min_ones + val.min_tens * 10; - hour = val.hr_ones + val.hr_tens * 10; - if (!hr24) { - if (hour == 12 || hour == 12 + 20) - hour -= 12; - if (hour >= 20) - hour += 12 - 20; - } - *hourp = hour; - *dayp = val.day_ones + val.day_tens * 10; - *monp = val.mon_ones + val.mon_tens * 10; - *yearp = val.year_ones + val.year_tens * 10 + 80; -} - - -static void atari_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - unsigned char ctrl; - unsigned short tos_version; - int hour, pm; - - while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; - while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; + /* + * On the Hades map the PCI memory, I/O and configuration areas + * (0x80000000 - 0xbfffffff). + * + * Settings: supervisor only, non-cacheable, serialized, read and write. + */ - *secp = RTC_READ(RTC_SECONDS); - *minp = RTC_READ(RTC_MINUTES); - hour = RTC_READ(RTC_HOURS); - *dayp = RTC_READ(RTC_DAY_OF_MONTH); - *monp = RTC_READ(RTC_MONTH); - *yearp = RTC_READ(RTC_YEAR); - pm = hour & 0x80; - hour &= ~0x80; - - ctrl = RTC_READ(RTC_CONTROL); - - if (!(ctrl & RTC_DM_BINARY)) { - BCD_TO_BIN(*secp); - BCD_TO_BIN(*minp); - BCD_TO_BIN(hour); - BCD_TO_BIN(*dayp); - BCD_TO_BIN(*monp); - BCD_TO_BIN(*yearp); - } - if (!(ctrl & RTC_24H)) { - if (!pm && hour == 12) - hour = 0; - else if (pm && hour != 12) - hour += 12; + if (MACH_IS_HADES) { + __asm__ __volatile__ ("movel %0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" + : /* no outputs */ + : "g" (0x803fa040) + : "d0"); } - *hourp = hour; - - /* Adjust values (let the setup valid) */ /* Fetch tos version at Physical 2 */ /* We my not be able to access this address if the kernel is @@ -647,403 +584,29 @@ we use the fact that in head.S we have set up a mapping 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible in the last 16MB of the address space. */ - tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xFF000002; - *yearp += (tos_version < 0x306) ? 70 : 68; + tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? + 0xfff : *(unsigned short *)0xff000002; + atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; } -#define HWCLK_POLL_INTERVAL 5 - -static int atari_mste_hwclk( int op, struct hwclk_time *t ) +#ifdef CONFIG_HEARTBEAT +static void atari_heartbeat( int on ) { - int hour, year; - int hr24=0; - struct MSTE_RTC val; - - mste_rtc.mode=(mste_rtc.mode | 1); - hr24=mste_rtc.mon_tens & 1; - mste_rtc.mode=(mste_rtc.mode & ~1); - - if (op) { - /* write: prepare values */ - - val.sec_ones = t->sec % 10; - val.sec_tens = t->sec / 10; - val.min_ones = t->min % 10; - val.min_tens = t->min / 10; - hour = t->hour; - if (!hr24) { - if (hour > 11) - hour += 20 - 12; - if (hour == 0 || hour == 20) - hour += 12; - } - val.hr_ones = hour % 10; - val.hr_tens = hour / 10; - val.day_ones = t->day % 10; - val.day_tens = t->day / 10; - val.mon_ones = (t->mon+1) % 10; - val.mon_tens = (t->mon+1) / 10; - year = t->year - 80; - val.year_ones = year % 10; - val.year_tens = year / 10; - val.weekday = t->wday; - mste_write(&val); - mste_rtc.mode=(mste_rtc.mode | 1); - val.year_ones = (year % 4); /* leap year register */ - mste_rtc.mode=(mste_rtc.mode & ~1); - } - else { - mste_read(&val); - t->sec = val.sec_ones + val.sec_tens * 10; - t->min = val.min_ones + val.min_tens * 10; - hour = val.hr_ones + val.hr_tens * 10; - if (!hr24) { - if (hour == 12 || hour == 12 + 20) - hour -= 12; - if (hour >= 20) - hour += 12 - 20; - } - t->hour = hour; - t->day = val.day_ones + val.day_tens * 10; - t->mon = val.mon_ones + val.mon_tens * 10 - 1; - t->year = val.year_ones + val.year_tens * 10 + 80; - t->wday = val.weekday; - } - return 0; -} + unsigned char tmp; + unsigned long flags; -static int atari_hwclk( int op, struct hwclk_time *t ) -{ - int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; - unsigned long flags; - unsigned short tos_version; - unsigned char ctrl; - int pm = 0; - - /* Tos version at Physical 2. See above for explanation why we - cannot use PTOV(2). */ - tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xff000002; - - ctrl = RTC_READ(RTC_CONTROL); /* control registers are - * independent from the UIP */ - - if (op) { - /* write: prepare values */ - - sec = t->sec; - min = t->min; - hour = t->hour; - day = t->day; - mon = t->mon + 1; - year = t->year - ((tos_version < 0x306) ? 70 : 68); - wday = t->wday + (t->wday >= 0); - - if (!(ctrl & RTC_24H)) { - if (hour > 11) { - pm = 0x80; - if (hour != 12) - hour -= 12; - } - else if (hour == 0) - hour = 12; - } - - if (!(ctrl & RTC_DM_BINARY)) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hour); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(year); - if (wday >= 0) BIN_TO_BCD(wday); - } - } + if (atari_dont_touch_floppy_select) + return; - /* Reading/writing the clock registers is a bit critical due to - * the regular update cycle of the RTC. While an update is in - * progress, registers 0..9 shouldn't be touched. - * The problem is solved like that: If an update is currently in - * progress (the UIP bit is set), the process sleeps for a while - * (50ms). This really should be enough, since the update cycle - * normally needs 2 ms. - * If the UIP bit reads as 0, we have at least 244 usecs until the - * update starts. This should be enough... But to be sure, - * additionally the RTC_SET bit is set to prevent an update cycle. - */ - - while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HWCLK_POLL_INTERVAL; - schedule(); - } - save_flags(flags); cli(); - RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); - if (!op) { - sec = RTC_READ( RTC_SECONDS ); - min = RTC_READ( RTC_MINUTES ); - hour = RTC_READ( RTC_HOURS ); - day = RTC_READ( RTC_DAY_OF_MONTH ); - mon = RTC_READ( RTC_MONTH ); - year = RTC_READ( RTC_YEAR ); - wday = RTC_READ( RTC_DAY_OF_WEEK ); - } - else { - RTC_WRITE( RTC_SECONDS, sec ); - RTC_WRITE( RTC_MINUTES, min ); - RTC_WRITE( RTC_HOURS, hour + pm); - RTC_WRITE( RTC_DAY_OF_MONTH, day ); - RTC_WRITE( RTC_MONTH, mon ); - RTC_WRITE( RTC_YEAR, year ); - if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); - } - RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); - restore_flags(flags); - - if (!op) { - /* read: adjust values */ - - if (hour & 0x80) { - hour &= ~0x80; - pm = 1; - } - - if (!(ctrl & RTC_DM_BINARY)) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - BCD_TO_BIN(wday); - } - - if (!(ctrl & RTC_24H)) { - if (!pm && hour == 12) - hour = 0; - else if (pm && hour != 12) - hour += 12; - } - - t->sec = sec; - t->min = min; - t->hour = hour; - t->day = day; - t->mon = mon - 1; - t->year = year + ((tos_version < 0x306) ? 70 : 68); - t->wday = wday - 1; - } - - return( 0 ); -} - - -static int atari_mste_set_clock_mmss (unsigned long nowtime) -{ - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - struct MSTE_RTC val; - unsigned char rtc_minutes; - - mste_read(&val); - rtc_minutes= val.min_ones + val.min_tens * 10; - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - val.sec_ones = real_seconds % 10; - val.sec_tens = real_seconds / 10; - val.min_ones = real_minutes % 10; - val.min_tens = real_minutes / 10; - mste_write(&val); - } - else - return -1; - return 0; -} - -static int atari_set_clock_mmss (unsigned long nowtime) -{ - int retval = 0; - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - unsigned char save_control, save_freq_select, rtc_minutes; - - save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ - RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); - - save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ - RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); - - rtc_minutes = RTC_READ (RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY)) - BCD_TO_BIN (rtc_minutes); - - /* Since we're only adjusting minutes and seconds, don't interfere - with hour overflow. This avoids messing with unknown time zones - but requires your RTC not to be off by more than 30 minutes. */ - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - if (!(save_control & RTC_DM_BINARY)) - { - BIN_TO_BCD (real_seconds); - BIN_TO_BCD (real_minutes); - } - RTC_WRITE (RTC_SECONDS, real_seconds); - RTC_WRITE (RTC_MINUTES, real_minutes); - } - else - retval = -1; - - RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); - RTC_WRITE (RTC_CONTROL, save_control); - return retval; -} - -static inline void ata_mfp_out (char c) -{ - while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ - barrier (); - mfp.usart_dta = c; -} - -static void atari_mfp_console_write (const char *str, unsigned int count) -{ - while (count--) { - if (*str == '\n') - ata_mfp_out( '\r' ); - ata_mfp_out( *str++ ); - } -} - -static inline void ata_scc_out (char c) -{ - do { - MFPDELAY(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - MFPDELAY(); - scc.cha_b_data = c; -} - -static void atari_scc_console_write (const char *str, unsigned int count) -{ - while (count--) { - if (*str == '\n') - ata_scc_out( '\r' ); - ata_scc_out( *str++ ); - } -} - -static int ata_par_out (char c) -{ - extern unsigned long loops_per_sec; - unsigned char tmp; - /* This a some-seconds timeout in case no printer is connected */ - unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; - - while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ - ; - if (!i) return( 0 ); - - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = c; /* put char onto port */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ - MFPDELAY(); /* wait a bit */ - sound_ym.wd_data = tmp | 0x20; /* set strobe H */ - return( 1 ); -} - -static void atari_par_console_write (const char *str, unsigned int count) -{ - static int printer_present = 1; - - if (!printer_present) - return; - - while (count--) { - if (*str == '\n') - if (!ata_par_out( '\r' )) { - printer_present = 0; - return; - } - if (!ata_par_out( *str++ )) { - printer_present = 0; - return; - } - } + sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); + restore_flags(flags); } - - -__initfunc(static void atari_debug_init(void)) -{ -#ifdef CONFIG_KGDB - /* if the m68k_debug_device is used by the GDB stub, do nothing here */ - if (kgdb_initialized) - return(NULL); #endif - if (!strcmp( m68k_debug_device, "ser" )) { - /* defaults to ser2 for a Falcon and ser1 otherwise */ - strcpy( m68k_debug_device, - ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON) ? - "ser2" : "ser1" ); - - } - - if (!strcmp( m68k_debug_device, "ser1" )) { - /* ST-MFP Modem1 serial port */ - mfp.trn_stat &= ~0x01; /* disable TX */ - mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */ - mfp.tim_ct_cd &= 0x70; /* stop timer D */ - mfp.tim_dt_d = 2; /* 9600 bps */ - mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ - mfp.trn_stat |= 0x01; /* enable TX */ - atari_console_driver.write = atari_mfp_console_write; - } - else if (!strcmp( m68k_debug_device, "ser2" )) { - /* SCC Modem2 serial port */ - static unsigned char *p, scc_table[] = { - 9, 12, /* Reset */ - 4, 0x44, /* x16, 1 stopbit, no parity */ - 3, 0xc0, /* receiver: 8 bpc */ - 5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */ - 9, 0, /* no interrupts */ - 10, 0, /* NRZ */ - 11, 0x50, /* use baud rate generator */ - 12, 24, 13, 0, /* 9600 baud */ - 14, 2, 14, 3, /* use master clock for BRG, enable */ - 3, 0xc1, /* enable receiver */ - 5, 0xea, /* enable transmitter */ - 0 - }; - - (void)scc.cha_b_ctrl; /* reset reg pointer */ - for( p = scc_table; *p != 0; ) { - scc.cha_b_ctrl = *p++; - MFPDELAY(); - scc.cha_b_ctrl = *p++; - MFPDELAY(); - } - atari_console_driver.write = atari_scc_console_write; - } - else if (!strcmp( m68k_debug_device, "par" )) { - /* parallel printer */ - atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ - sound_ym.rd_data_reg_sel = 7; /* select mixer control */ - sound_ym.wd_data = 0xff; /* sound off, ports are output */ - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = 0; /* no char */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ - atari_console_driver.write = atari_par_console_write; - } - if (atari_console_driver.write) - register_console(&atari_console_driver); -} - /* ++roman: * * This function does a reset on machines that lack the ability to @@ -1082,11 +645,16 @@ /* On the Medusa, phys. 0x4 may contain garbage because it's no ROM. See above for explanation why we cannot use PTOV(4). */ - reset_addr = is_hades ? 0x7fe00030 : - (is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004); - - acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */ - + reset_addr = MACH_IS_HADES ? 0x7fe00030 : + MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : + *(unsigned long *) 0xff000004; + + /* reset ACIA for switch off OverScan, if it's active */ + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_RESET; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_RESET; + /* processor independent: turn off interrupts and reset the VBR; * the caches must be left enabled, else prefetching the final jump * instruction doesn't work. */ @@ -1126,8 +694,21 @@ "nop\n\t" ".chip 68040\n\t" "cinva %%bc\n\t" + "nop\n\t" "pflusha\n\t" + "nop\n\t" "movec %%d0,%%tc\n\t" + "nop\n\t" + /* the following setup of transparent translations is needed on the + * Afterburner040 to successfully reboot. Other machines shouldn't + * care about a different tt regs setup, they also didn't care in + * the past that the regs weren't turned off. */ + "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%itt1\n\t" + "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ + "movec %%d0,%%dtt0\n\t" + "movec %%d0,%%dtt1\n\t" ".chip 68k\n\t" "jmp %0@" : /* no outputs */ @@ -1154,22 +735,24 @@ strcat (model, "ST"); break; case ATARI_MCH_STE: - if ((atari_mch_cookie & 0xffff) == 0x10) + if (MACH_IS_MSTE) strcat (model, "Mega STE"); else strcat (model, "STE"); break; case ATARI_MCH_TT: - if (is_medusa) + if (MACH_IS_MEDUSA) /* Medusa has TT _MCH cookie */ strcat (model, "Medusa"); - else if (is_hades) + else if (MACH_IS_HADES) strcat(model, "Hades"); else strcat (model, "TT"); break; case ATARI_MCH_FALCON: strcat (model, "Falcon"); + if (MACH_IS_AB40) + strcat (model, " (with Afterburner040)"); break; default: sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", @@ -1225,3 +808,10 @@ return(len); } + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/debug.c linux/arch/m68k/atari/debug.c --- v2.1.86/linux/arch/m68k/atari/debug.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/atari/debug.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,359 @@ +/* + * linux/arch/m68k/atari/debug.c + * + * Atari debugging and serial console stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * 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 + +extern char m68k_debug_device[]; + +/* Flag that Modem1 port is already initialized and used */ +int atari_MFP_init_done = 0; +/* Flag that Modem1 port is already initialized and used */ +int atari_SCC_init_done = 0; +/* Can be set somewhere, if a SCC master reset has already be done and should + * not be repeated; used by kgdb */ +int atari_SCC_reset_done = 0; + +static struct console atari_console_driver = { + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + NULL, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +static inline void ata_mfp_out (char c) +{ + while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ + barrier (); + mfp.usart_dta = c; +} + +void atari_mfp_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_mfp_out( '\r' ); + ata_mfp_out( *str++ ); + } +} + +static inline void ata_scc_out (char c) +{ + do { + MFPDELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + MFPDELAY(); + scc.cha_b_data = c; +} + +void atari_scc_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_scc_out( '\r' ); + ata_scc_out( *str++ ); + } +} + +static inline void ata_midi_out (char c) +{ + while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ + barrier (); + acia.mid_data = c; +} + +void atari_midi_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_midi_out( '\r' ); + ata_midi_out( *str++ ); + } +} + +static int ata_par_out (char c) +{ + unsigned char tmp; + /* This a some-seconds timeout in case no printer is connected */ + unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; + + while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ + ; + if (!i) return( 0 ); + + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = c; /* put char onto port */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ + MFPDELAY(); /* wait a bit */ + sound_ym.wd_data = tmp | 0x20; /* set strobe H */ + return( 1 ); +} + +static void atari_par_console_write (struct console *co, const char *str, + unsigned int count) +{ + static int printer_present = 1; + + if (!printer_present) + return; + + while (count--) { + if (*str == '\n') + if (!ata_par_out( '\r' )) { + printer_present = 0; + return; + } + if (!ata_par_out( *str++ )) { + printer_present = 0; + return; + } + } +} + +#ifdef CONFIG_SERIAL_CONSOLE +int atari_mfp_console_wait_key(struct console *co) +{ + while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ + barrier(); + return( mfp.usart_dta ); +} + +int atari_scc_console_wait_key(struct console *co) +{ + do { + MFPDELAY(); + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + MFPDELAY(); + return( scc.cha_b_data ); +} + +int atari_midi_console_wait_key(struct console *co) +{ + while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ + barrier(); + return( acia.mid_data ); +} +#endif + +/* The following two functions do a quick'n'dirty initialization of the MFP or + * SCC serial ports. They're used by the debugging interface, kgdb, and the + * serial console code. */ +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_mfp_port( int cflag )) +#else +void atari_init_mfp_port( int cflag ) +#endif +{ + /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 + * bps, resp., and work only correct if there's a RSVE or RSSPEED */ + static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; + int baud = cflag & CBAUD; + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; + int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* baud_table[] starts at 1200bps */ + + mfp.trn_stat &= ~0x01; /* disable TX */ + mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ + mfp.tim_ct_cd &= 0x70; /* stop timer D */ + mfp.tim_dt_d = baud_table[baud]; + mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ + mfp.trn_stat |= 0x01; /* enable TX */ + + atari_MFP_init_done = 1; +} + +#define SCC_WRITE(reg,val) \ + do { \ + scc.cha_b_ctrl = (reg); \ + MFPDELAY(); \ + scc.cha_b_ctrl = (val); \ + MFPDELAY(); \ + } while(0) + +/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a + * delay of ~ 60us. */ +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 100; i > 0; --i ) \ + MFPDELAY(); \ + } while(0) + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_scc_port( int cflag )) +#else +void atari_init_scc_port( int cflag ) +#endif +{ + extern int atari_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { + /* special treatment for TT, where rates >= 38400 are done via TRxC */ + clksrc = 0x28; /* TRxC */ + clkmode = baud == 6 ? 0xc0 : + baud == 7 ? 0x80 : /* really 76800bps */ + 0x40; /* really 153600bps */ + div = 0; + } + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCC_WRITE( 3, reg3 ); + SCC_WRITE( 5, reg5 ); + SCC_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 10, 0 ); /* NRZ mode */ + SCC_WRITE( 11, clksrc ); /* main clock source */ + SCC_WRITE( 12, div ); /* BRG value */ + SCC_WRITE( 13, 0 ); /* BRG high byte */ + SCC_WRITE( 14, brgsrc_table[baud] ); + SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCC_WRITE( 3, reg3 | 1 ); + SCC_WRITE( 5, reg5 | 8 ); + + atari_SCC_reset_done = 1; + atari_SCC_init_done = 1; +} + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_midi_port( int cflag )) +#else +void atari_init_midi_port( int cflag ) +#endif +{ + int baud = cflag & CBAUD; + int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; + /* warning 7N1 isn't possible! (instead 7O2 is used...) */ + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; + int div; + + /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as + * default) the standard MIDI speed 31250. */ + if (cflag & CBAUDEX) + baud += B38400; + if (baud == B4800) + div = ACIA_DIV64; /* really 7812.5 bps */ + else if (baud == B38400+2 /* 115200 */) + div = ACIA_DIV1; /* really 500 kbps (does that work??) */ + else + div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ + + /* RTS low, ints disabled */ + acia.mid_ctrl = div | csize | parity | + ((atari_switches & ATARI_SWITCH_MIDI) ? + ACIA_RHTID : ACIA_RLTID); +} + +__initfunc(void atari_debug_init(void)) +{ +#ifdef CONFIG_KGDB + /* the m68k_debug_device is used by the GDB stub, do nothing here */ + return; +#endif + if (!strcmp( m68k_debug_device, "ser" )) { + /* defaults to ser2 for a Falcon and ser1 otherwise */ + strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); + + } + + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + atari_init_mfp_port( B9600|CS8 ); + atari_console_driver.write = atari_mfp_console_write; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + atari_init_scc_port( B9600|CS8 ); + atari_console_driver.write = atari_scc_console_write; + } + else if (!strcmp( m68k_debug_device, "midi" )) { + /* MIDI port */ + atari_init_midi_port( B9600|CS8 ); + atari_console_driver.write = atari_midi_console_write; + } + else if (!strcmp( m68k_debug_device, "par" )) { + /* parallel printer */ + atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ + sound_ym.wd_data = 0xff; /* sound off, ports are output */ + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = 0; /* no char */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ + atari_console_driver.write = atari_par_console_write; + } + if (atari_console_driver.write) + register_console(&atari_console_driver); +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c --- v2.1.86/linux/arch/m68k/atari/joystick.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/atari/joystick.c Thu Feb 12 16:30:12 1998 @@ -82,15 +82,16 @@ return 0; } -static long write_joystick(struct inode *inode, struct file *file, - const char *buffer, unsigned long count) +static ssize_t write_joystick(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; } -static long read_joystick(struct inode *inode, struct file *file, - char *buffer, unsigned long count) +static ssize_t read_joystick(struct file *file, char *buffer, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int minor = DEVICE_NR(inode->i_rdev); if (count < 2) @@ -109,7 +110,7 @@ static unsigned int joystick_poll(struct file *file, poll_table *wait) { - int minor = DEVICE_NR(file->f_inode->i_rdev); + int minor = DEVICE_NR(file->f_dentry->d_inode->i_rdev); poll_wait(&joystick[minor].wait, wait); if (joystick[minor].ready) diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c --- v2.1.86/linux/arch/m68k/atari/stdma.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/atari/stdma.c Thu Feb 12 16:30:12 1998 @@ -1,6 +1,5 @@ - /* - * linux/atari/stmda.c + * linux/arch/m68k/atari/stmda.c * * Copyright (C) 1994 Roman Hodek * @@ -37,7 +36,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c --- v2.1.86/linux/arch/m68k/atari/stram.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/atari/stram.c Thu Feb 12 16:30:12 1998 @@ -1,157 +1,56 @@ +/* + * arch/m68k/atari/stram.c: Functions for ST-RAM allocations + * + * Copyright 1994-97 Roman Hodek + * + * 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 -#if 0 - -struct stram_desc - { - unsigned first:1; - unsigned last:1; - unsigned alloced:1; - unsigned length:24; - }; - -#define DP(ptr) ((struct stram_desc *) (ptr)) - -static unsigned long stramsize; -static unsigned long stramaddr; - -void -atari_stram_init (void) -{ - struct stram_desc *dp; - stramaddr = atari_stram_start; - stramsize = atari_stram_size; - - /* initialize start boundary */ - dp = DP (stramaddr); - dp->first = 1; - dp->alloced = 0; - dp->length = stramsize - 2 * sizeof (*dp); - - /* initialize end boundary */ - dp = DP (stramaddr + stramsize) - 1; - dp->last = 1; - dp->alloced = 0; - dp->length = stramsize - 2 * sizeof (*dp); - -#ifdef DEBUG - printk ("stram end boundary is %p, length is %d\n", dp, - dp->length); -#endif -} - -void * -atari_stram_alloc (long size) -{ - /* last chunk */ - struct stram_desc *dp; - void *ptr; - - /* round off */ - size = (size + 3) & ~3; -#ifdef DEBUG - printk ("stram_alloc: allocate %ld bytes\n", size); +#ifdef CONFIG_STRAM_SWAP +#define MAJOR_NR Z2RAM_MAJOR +#include +#undef DEVICE_NAME +#define DEVICE_NAME "stram" #endif - /* - * get pointer to descriptor for last chunk by - * going backwards from end chunk - */ - dp = DP (stramaddr + stramsize) - 1; - dp = DP ((unsigned long) dp - dp->length) - 1; - - while ((dp->alloced || dp->length < size) && !dp->first) - dp = DP ((unsigned long) dp - dp[-1].length) - 2; - - if (dp->alloced || dp->length < size) - { - printk ("no stram available for %ld allocation\n", size); - return NULL; - } - - if (dp->length < size + 2 * sizeof (*dp)) - { - /* length too small to split; allocate the whole thing */ - dp->alloced = 1; - ptr = (void *) (dp + 1); - dp = DP ((unsigned long) ptr + dp->length); - dp->alloced = 1; -#ifdef DEBUG - printk ("stram_alloc: no split\n"); -#endif - } - else - { - /* split the extent; use the end part */ - long newsize = dp->length - (2 * sizeof (*dp) + size); +#undef DEBUG #ifdef DEBUG - printk ("stram_alloc: splitting %d to %ld\n", dp->length, - newsize); +#define DPRINTK(fmt,args...) printk( fmt, ##args ) +#else +#define DPRINTK(fmt,args...) #endif - dp->length = newsize; - dp = DP ((unsigned long) (dp + 1) + newsize); - dp->first = dp->last = 0; - dp->alloced = 0; - dp->length = newsize; - dp++; - dp->first = dp->last = 0; - dp->alloced = 1; - dp->length = size; - ptr = (void *) (dp + 1); - dp = DP ((unsigned long) ptr + size); - dp->alloced = 1; - dp->length = size; - } -#ifdef DEBUG - printk ("stram_alloc: returning %p\n", ptr); +#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC) +/* abbrev for the && above... */ +#define DO_PROC +#include #endif - return ptr; -} - -void -atari_stram_free (void *ptr) -{ - struct stram_desc *sdp = DP (ptr) - 1, *dp2; - struct stram_desc *edp = DP ((unsigned long) ptr + sdp->length); - - /* deallocate the chunk */ - sdp->alloced = edp->alloced = 0; - /* check if we should merge with the previous chunk */ - if (!sdp->first && !sdp[-1].alloced) - { - dp2 = DP ((unsigned long) sdp - sdp[-1].length) - 2; - dp2->length += sdp->length + 2 * sizeof (*sdp); - edp->length = dp2->length; - sdp = dp2; - } - - /* check if we should merge with the following chunk */ - if (!edp->last && !edp[1].alloced) - { - dp2 = DP ((unsigned long) edp + edp[1].length) + 2; - dp2->length += edp->length + 2 * sizeof (*sdp); - sdp->length = dp2->length; - edp = dp2; - } -} - -#else - -#include -#include - -/* ++roman: +/* Pre-swapping comments: + * + * ++roman: * * New version of ST-Ram buffer allocation. Instead of using the * 1 MB - 4 KB that remain when the the ST-Ram chunk starts at $1000 @@ -173,72 +72,1414 @@ * no provision now for freeing ST-Ram buffers. It seems that isn't * really needed. * - * ToDo: - * Check the high level scsi code what is done when the - * UNCHECKED_ISA_DMA flag is set. It guess, it is just a test for adr - * < 16 Mega. There should be call to atari_stram_alloc() instead. - * - * Also ToDo: - * Go through head.S and delete parts no longer needed (transparent - * mapping of ST-Ram etc.) + */ + +/* + * New Nov 1997: Use ST-RAM as swap space! + * + * In the past, there were often problems with modules that require ST-RAM + * buffers. Such drivers have to use __get_dma_pages(), which unfortunately + * often isn't very successful in allocating more than 1 page :-( [1] The net + * result was that most of the time you couldn't insmod such modules (ataflop, + * ACSI, SCSI on Falcon, Atari internal framebuffer, not to speak of acsi_slm, + * which needs a 1 MB buffer... :-). + * + * To overcome this limitation, ST-RAM can now be turned into a very + * high-speed swap space. If a request for an ST-RAM buffer comes, the kernel + * now tries to unswap some pages on that swap device to make some free (and + * contiguous) space. This works much better in comparison to + * __get_dma_pages(), since used swap pages can be selectively freed by either + * moving them to somewhere else in swap space, or by reading them back into + * system memory. Ok, there operation of unswapping isn't really cheap (for + * each page, one has to go through the page tables of all processes), but it + * doesn't happen that often (only when allocation ST-RAM, i.e. when loading a + * module that needs ST-RAM). But it at least makes it possible to load such + * modules! + * + * It could also be that overall system performance increases a bit due to + * ST-RAM swapping, since slow ST-RAM isn't used anymore for holding data or + * executing code in. It's then just a (very fast, compared to disk) back + * storage for not-so-often needed data. (But this effect must be compared + * with the loss of total memory...) Don't know if the effect is already + * visible on a TT, where the speed difference between ST- and TT-RAM isn't + * that dramatic, but it should on machines where TT-RAM is really much faster + * (e.g. Afterburner). * + * [1]: __get_free_pages() does a fine job if you only want one page, but if + * you want more (contiguous) pages, it can give you such a block only if + * there's already a free one. The algorithm can't try to free buffers or swap + * out something in order to make more free space, since all that page-freeing + * mechanisms work "target-less", i.e. they just free something, but not in a + * specific place. I.e., __get_free_pages() can't do anything to free + * *adjacent* pages :-( This situation becomes even worse for DMA memory, + * since the freeing algorithms are also blind to DMA capability of pages. + */ + +#ifdef CONFIG_STRAM_SWAP +#define ALIGN_IF_SWAP(x) PAGE_ALIGN(x) +#else +#define ALIGN_IF_SWAP(x) (x) +#endif + +/* map entry for reserved swap page (used as buffer) */ +#define SWP_RSVD 0x80 + +/* get index of swap page at address 'addr' */ +#define SWAP_NR(addr) (((unsigned long)(addr)-swap_start) >> PAGE_SHIFT) + +/* get address of swap page #'nr' */ +#define SWAP_ADDR(nr) ((void *)(swap_start + ((nr)<> PAGE_SHIFT) + +/* The following two numbers define the maximum fraction of ST-RAM in total + * memory, below that the kernel would automatically use ST-RAM as swap + * space. This decision can be overriden with stram_swap= */ +#define MAX_STRAM_FRACTION_NOM 1 +#define MAX_STRAM_FRACTION_DENOM 3 + +/* Start and end of the (pre-mem_init) reserved ST-RAM region */ +static unsigned long rsvd_stram_beg, rsvd_stram_end; + +/* Start and end (virtual) of ST-RAM */ +static unsigned long stram_start, stram_end; + +/* set after memory_init() executed and allocations via start_mem aren't + * possible anymore */ +static int mem_init_done = 0; + +/* set if kernel is in ST-RAM */ +static int kernel_in_stram; + +typedef struct stram_block { + struct stram_block *next; + unsigned long start; + unsigned long size; + unsigned flags; + const char *owner; +} BLOCK; + +/* values for flags field */ +#define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */ +#define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */ +#define BLOCK_STATIC 0x04 /* pre-mem_init() allocated block */ +#define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */ +#define BLOCK_INSWAP 0x10 /* block allocated in swap space */ + +/* list of allocated blocks */ +static BLOCK *alloc_list = NULL; + +/* We can't always use kmalloc() to allocate BLOCK structures, since + * stram_alloc() can be called rather early. So we need some pool of + * statically allocated structures. 20 of them is more than enough, so in most + * cases we never should need to call kmalloc(). */ +#define N_STATIC_BLOCKS 20 +static BLOCK static_blocks[N_STATIC_BLOCKS]; + +#ifdef CONFIG_STRAM_SWAP +/* max. number of bytes to use for swapping + * 0 = no ST-RAM swapping + * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of + * total memory */ - +static int max_swap_size = -1; -unsigned long rsvd_stram_beg, rsvd_stram_end; - /* Start and end of the reserved ST-Ram region */ -static unsigned long stram_end; - /* Overall end of ST-Ram */ +/* start and end of swapping area */ +static unsigned long swap_start, swap_end; +/* The ST-RAM's swap info structure */ +static struct swap_info_struct *stram_swap_info; +/* The ST-RAM's swap type */ +static int stram_swap_type; + +/* major and minor device number of the ST-RAM device; for the major, we use + * the same as Amiga z2ram, which is really similar and impossible on Atari, + * and for the minor a relatively odd number to avoid the user creating and + * using that device. */ +#define STRAM_MAJOR Z2RAM_MAJOR +#define STRAM_MINOR 13 + +/* Some impossible pointer value */ +#define MAGIC_FILE_P (struct file *)0xffffdead + +#ifdef DO_PROC +static unsigned stat_swap_read = 0; +static unsigned stat_swap_write = 0; +static unsigned stat_swap_move = 0; +static unsigned stat_swap_force = 0; +#endif /* DO_PROC */ + +#endif /* CONFIG_STRAM_SWAP */ + +/***************************** Prototypes *****************************/ + +#ifdef CONFIG_STRAM_SWAP +static int swap_init( unsigned long start_mem, unsigned long swap_data ); +static inline int unswap_pte( struct vm_area_struct * vma, unsigned long + address, pte_t *dir, unsigned long entry, + unsigned long page, int isswap ); +static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, + unsigned long offset, unsigned long entry, + unsigned long page, int isswap ); +static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned long entry, unsigned long page, int + isswap ); +static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, unsigned + long entry, unsigned long page, int isswap ); +static int unswap_process( struct mm_struct * mm, unsigned long entry, + unsigned long page, int isswap ); +static int unswap_by_move( unsigned char *map, unsigned long max, unsigned + long start, unsigned long n_pages ); +static int unswap_by_read( unsigned char *map, unsigned long max, unsigned + long start, unsigned long n_pages ); +static void *get_stram_region( unsigned long n_pages ); +static void free_stram_region( unsigned long offset, unsigned long n_pages + ); +static int in_some_region( unsigned long addr ); +static unsigned long find_free_region( unsigned long n_pages, unsigned long + *total_free, unsigned long + *region_free ); +static void do_stram_request( void ); +static int stram_open( struct inode *inode, struct file *filp ); +static int stram_release( struct inode *inode, struct file *filp ); +static void do_z2_request( void ); +#endif +static int get_gfp_order( unsigned long size ); +static void reserve_region( unsigned long addr, unsigned long end ); +static BLOCK *add_region( void *addr, unsigned long size ); +static BLOCK *find_region( void *addr ); +static int remove_region( BLOCK *block ); + +/************************* End of Prototypes **************************/ + + +/* ------------------------------------------------------------------------ */ +/* Public Interface */ +/* ------------------------------------------------------------------------ */ + +/* + * This init function is called very early by atari/config.c + * It initializes some internal variables needed for stram_alloc() + */ __initfunc(void atari_stram_init( void )) +{ + int i; -{ int i; + /* initialize static blocks */ + for( i = 0; i < N_STATIC_BLOCKS; ++i ) + static_blocks[i].flags = BLOCK_FREE; + + /* determine whether kernel code resides in ST-RAM (then ST-RAM is the + * first memory block at virtual 0x0) */ + stram_start = PTOV( 0 ); + kernel_in_stram = (stram_start == 0); for( i = 0; i < m68k_num_memory; ++i ) { if (m68k_memory[i].addr == 0) { - rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */ + /* skip first 2kB or page (supervisor-only!) */ + rsvd_stram_beg = stram_start + ALIGN_IF_SWAP(0x800); rsvd_stram_end = rsvd_stram_beg; - stram_end = rsvd_stram_beg - 0x800 + m68k_memory[i].size; + stram_end = stram_start + m68k_memory[i].size; return; } } /* Should never come here! (There is always ST-Ram!) */ + panic( "atari_stram_init: no ST-RAM found!" ); } -void *atari_stram_alloc( long size, unsigned long *start_mem ) +/* + * This function is called from mem_init() to reserve the pages needed for + * ST-RAM management. + */ +__initfunc(void atari_stram_reserve_pages( unsigned long start_mem )) +{ +#ifdef CONFIG_STRAM_SWAP + /* if max_swap_size is negative (i.e. no stram_swap= option given), + * determine at run time whether to use ST-RAM swapping */ + if (max_swap_size < 0) + /* Use swapping if ST-RAM doesn't make up more than MAX_STRAM_FRACTION + * of total memory. In that case, the max. size is set to 16 MB, + * because ST-RAM can never be bigger than that. + * Also, never use swapping on a Hades, there's no separate ST-RAM in + * that machine. */ + max_swap_size = + (!MACH_IS_HADES && + (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <= + max_mapnr*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; + DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size ); +#endif + /* always reserve first page of ST-RAM, the first 2 kB are + * supervisor-only! */ + set_bit( PG_reserved, &mem_map[MAP_NR(stram_start)].flags ); + +#ifdef CONFIG_STRAM_SWAP + if (!max_swap_size) { + fallback: +#endif + DPRINTK( "atari_stram_reserve_pages: swapping disabled\n" ); + if (!kernel_in_stram) { + /* Reserve all pages that have been marked by pre-mem_init + * stram_alloc() (e.g. for the screen memory). */ + reserve_region( rsvd_stram_beg, rsvd_stram_end ); + DPRINTK( "atari_stram_reserve_pages: reseverved %08lx-%08lx\n", + rsvd_stram_beg, rsvd_stram_end ); + } + /* else (kernel in ST-RAM): nothing to do, ST-RAM buffers are + * kernel data */ +#ifdef CONFIG_STRAM_SWAP + } + else { + unsigned long swap_data; + BLOCK *p; + + /* determine first page to use as swap: + * if the kernel is in TT-RAM, this is the first page of (usable) + * ST-RAM; else if there were already some allocations (probable...), + * use the lowest address of these (the list is sorted by address!); + * otherwise just use the end of kernel data (= start_mem) */ + swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : + alloc_list ? alloc_list->start : + start_mem; + /* decrement by one page, rest of kernel assumes that first swap page + * is always reserved and maybe doesn't handle SWP_ENTRY == 0 + * correctly */ + swap_start -= PAGE_SIZE; + swap_end = stram_end; + if (swap_end-swap_start > max_swap_size) + swap_end = swap_start + max_swap_size; + DPRINTK( "atari_stram_reserve_pages: swapping enabled; " + "swap=%08lx-%08lx\n", swap_start, swap_end ); + + /* reserve some amount of memory for maintainance of swapping itself: + * 1 page for the lockmap, and one page for each 4096 (PAGE_SIZE) swap + * pages. (1 byte for each page) */ + swap_data = start_mem; + start_mem += PAGE_ALIGN(SWAP_NR(swap_end)) + PAGE_SIZE; + /* correct swap_start if necessary */ + if (swap_start == swap_data) + swap_start = start_mem; + + if (!swap_init( start_mem, swap_data )) { + printk( KERN_ERR "ST-RAM swap space initialization failed\n" ); + max_swap_size = 0; + goto fallback; + } + /* reserve region for swapping meta-data */ + reserve_region( swap_data, start_mem ); + /* reserve swapping area itself */ + reserve_region( swap_start+PAGE_SIZE, swap_end ); + + /* Formerly static areas have been included in the swap area. */ + for( p = alloc_list; p; p = p->next ) { + if (p->flags & BLOCK_STATIC) + p->flags = (p->flags & ~BLOCK_STATIC) | BLOCK_INSWAP; + } + + /* + * If the whole ST-RAM is used for swapping, there are no allocatable + * dma pages left. But unfortunately, some shared parts of the kernel + * (particularily the SCSI mid-level) call __get_dma_pages() + * unconditionally :-( These calls then fail, and scsi.c even doesn't + * check for NULL return values and just crashes. The quick fix for + * this (instead of doing much clean up work in the SCSI code) is to + * pretend all pages are DMA-able by setting mach_max_dma_address to + * ULONG_MAX. This doesn't change any functionality so far, since + * get_dma_pages() shouldn't be used on Atari anyway anymore (better + * use atari_stram_alloc()), and the Atari SCSI drivers don't need DMA + * memory. But unfortunately there's now no kind of warning (even not + * a NULL return value) if you use get_dma_pages() nevertheless :-( + * You just will get non-DMA-able memory... + */ + mach_max_dma_address = 0xffffffff; + + /* + * Ok, num_physpages needs not be really exact, but it's better to + * subtract the pages set aside for swapping. + */ + num_physpages -= SWAP_NR(swap_end)-1; + } +#endif + + mem_init_done = 1; +} + + +/* + * This is main public interface: somehow allocate a ST-RAM block + * There are three strategies: + * + * - If we're before mem_init(), we have to make a static allocation. The + * region is taken in the kernel data area (if the kernel is in ST-RAM) or + * from the start of ST-RAM (if the kernel is in TT-RAM) and added to the + * rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel + * address space in the latter case. + * + * - If mem_init() already has been called and ST-RAM swapping is enabled, + * try to get the memory from the (pseudo) swap-space, either free already + * or by moving some other pages out of the swap. + * + * - If mem_init() already has been called, and ST-RAM swapping is not + * enabled, the only possibility is to try with __get_dma_pages(). This has + * the disadvantage that it's very hard to get more than 1 page, and it is + * likely to fail :-( + * + */ +void *atari_stram_alloc( long size, unsigned long *start_mem, + const char *owner ) { - static int kernel_in_stram = -1; + void *addr = NULL; + BLOCK *block; + int flags; + + DPRINTK( "atari_stram_alloc(size=%08lx,*start_mem=%08lx,owner=%s)\n", + size, start_mem ? *start_mem : 0xffffffff, owner ); - void *adr = 0; + if (start_mem && mem_init_done) { + printk( KERN_ERR "atari_stram_alloc called with start_mem!=NULL " + "after mem_init() from %p\n", __builtin_return_address(0) ); + return( NULL ); + } + if (!start_mem && !mem_init_done) { + printk( KERN_ERR "atari_stram_alloc called with start_mem==NULL " + "before mem_init() from %p\n", __builtin_return_address(0) ); + return( NULL ); + } + + size = ALIGN_IF_SWAP(size); + DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size ); + if (!mem_init_done) { + /* before mem_init(): allocate "statically", i.e. either in the kernel + * data space (current end in *start_mem), or at the end of currently + * reserved ST-RAM. */ + if (kernel_in_stram) { + /* Get memory from kernel data space */ + *start_mem = ALIGN_IF_SWAP(*start_mem); + addr = (void *)*start_mem; + *start_mem += size; + DPRINTK( "atari_stram_alloc: pre-mem_init and k/ST: " + "shifted start_mem to %08lx, addr=%p\n", + *start_mem, addr ); + } + else { + /* Get memory from rsvd_stram_beg */ + if (rsvd_stram_end + size < stram_end) { + addr = (void *) rsvd_stram_end; + rsvd_stram_end += size; + DPRINTK( "atari_stram_alloc: pre-mem_init and k/TT: " + "shifted rsvd_stram_end to %08lx, addr=%p\n", + rsvd_stram_end, addr ); + } + } + flags = BLOCK_STATIC; + } +#ifdef CONFIG_STRAM_SWAP + else if (max_swap_size) { + /* If swapping is active (can only be the case after mem_init()!): + * make some free space in the swap "device". */ + DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, " + "calling get_region\n" ); + addr = get_stram_region( N_PAGES(size) ); + flags = BLOCK_INSWAP; + } +#endif + else { + /* After mem_init() and no swapping: can only resort to + * __get_dma_pages() */ + addr = (void *)__get_dma_pages(GFP_KERNEL, get_gfp_order(size)); + flags = BLOCK_GFP; + DPRINTK( "atari_stram_alloc: after mem_init, swapping off, " + "get_pages=%p\n", addr ); + } + + if (addr) { + if (!(block = add_region( addr, size ))) { + /* out of memory for BLOCK structure :-( */ + DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " + "freeing again\n" ); + if (flags == BLOCK_STATIC) + rsvd_stram_end -= size; +#ifdef CONFIG_STRAM_SWAP + else if (flags == BLOCK_INSWAP) + free_stram_region( SWAP_NR(addr), N_PAGES(size) ); +#endif + else + free_pages( (unsigned long)addr, get_gfp_order(size)); + return( NULL ); + } + block->owner = owner; + block->flags |= flags; + } + return( addr ); +} + +void atari_stram_free( void *addr ) + +{ + BLOCK *block; + + DPRINTK( "atari_stram_free(addr=%p)\n", addr ); + + if (!(block = find_region( addr ))) { + printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " + "from %p\n", addr, __builtin_return_address(0) ); + return; + } + DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, " + "flags=%02x\n", block, block->size, block->owner, block->flags ); - if (kernel_in_stram < 0) - kernel_in_stram = (PTOV( 0 ) == 0); +#ifdef CONFIG_STRAM_SWAP + if (!max_swap_size) { +#endif + if (block->flags & BLOCK_GFP) { + DPRINTK( "atari_stram_free: is kmalloced, order_size=%d\n", + get_gfp_order(block->size) ); + free_pages( (unsigned long)addr, get_gfp_order(block->size) ); + } + else + goto fail; +#ifdef CONFIG_STRAM_SWAP + } + else if (block->flags & (BLOCK_INSWAP|BLOCK_STATIC)) { + DPRINTK( "atari_stram_free: is swap-alloced\n" ); + free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) ); + } + else + goto fail; +#endif + remove_region( block ); + return; + + fail: + printk( KERN_ERR "atari_stram_free: cannot free block at %p " + "(called from %p)\n", addr, __builtin_return_address(0) ); +} + + +#ifdef CONFIG_STRAM_SWAP + + +/* ------------------------------------------------------------------------ */ +/* Main Swapping Functions */ +/* ------------------------------------------------------------------------ */ - if (kernel_in_stram) { - /* Get memory from kernel data space */ - adr = (void *) *start_mem; - *start_mem += size; + +/* + * Initialize ST-RAM swap device + * (lots copied and modified from sys_swapon() in mm/swapfile.c) + */ +__initfunc(static int swap_init( unsigned long start_mem, + unsigned long swap_data )) +{ + static struct dentry fake_dentry[3]; + struct swap_info_struct *p; + struct inode swap_inode; + unsigned int type; + unsigned long addr; + int i, j, k, prev; + + DPRINTK( "swap_init(start_mem=%08lx, swap_data=%08lx)\n", + start_mem, swap_data ); + + /* need at least one page for swapping to (and this also isn't very + * much... :-) */ + if (swap_end - swap_start < 2*PAGE_SIZE) { + printk( KERN_WARNING "stram_swap_init: swap space too small\n" ); + return( 0 ); + } + + /* find free slot in swap_info */ + for( p = swap_info, type = 0; type < nr_swapfiles; type++, p++ ) + if (!(p->flags & SWP_USED)) + break; + if (type >= MAX_SWAPFILES) { + printk( KERN_WARNING "stram_swap_init: max. number of " + "swap devices exhausted\n" ); + return( 0 ); + } + if (type >= nr_swapfiles) + nr_swapfiles = type+1; + + stram_swap_info = p; + stram_swap_type = type; + + /* fake some dir cache entries to give us some name in /dev/swaps */ + fake_dentry[0].d_covers = &fake_dentry[1]; + fake_dentry[0].d_parent = &fake_dentry[0]; + fake_dentry[1].d_parent = &fake_dentry[2]; + fake_dentry[1].d_name.name = "stram (internal)"; + fake_dentry[1].d_name.len = 16; + fake_dentry[2].d_covers = &fake_dentry[2]; + fake_dentry[2].d_parent = &fake_dentry[2]; + + p->flags = SWP_USED; + p->swap_file = &fake_dentry[0]; + p->swap_device = 0; + p->swap_lockmap = (unsigned char *)(swap_data); + p->swap_map = (unsigned char *)(swap_data + PAGE_SIZE); + p->cluster_nr = 0; + p->next = -1; + p->prio = 0x7ff0; /* a rather high priority, but not the higest + * to give the user a chance to override */ + + /* call stram_open() directly, avoids at least the overhead in + * constructing a dummy file structure... */ + p->swap_device = MKDEV( STRAM_MAJOR, STRAM_MINOR ); + swap_inode.i_rdev = p->swap_device; + stram_open( &swap_inode, MAGIC_FILE_P ); + p->max = SWAP_NR(swap_end); + + /* initialize lockmap */ + memset( p->swap_lockmap, 0, PAGE_SIZE ); + + /* initialize swap_map: set regions that are already allocated or belong + * to kernel data space to SWP_RSVD, otherwise to free */ + j = 0; /* # of free pages */ + k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */ + p->lowest_bit = 0; + p->highest_bit = 0; + for( i = 1, addr = (unsigned long)SWAP_ADDR(1); i < p->max; + i++, addr += PAGE_SIZE ) { + if (in_some_region( addr )) { + p->swap_map[i] = SWP_RSVD; + ++k; + } + else if (kernel_in_stram && addr < start_mem ) { + p->swap_map[i] = SWP_RSVD; + } + else { + p->swap_map[i] = 0; + ++j; + if (!p->lowest_bit) p->lowest_bit = i; + p->highest_bit = i; + } + } + /* first page always reserved (and doesn't really belong to swap space) */ + p->swap_map[0] = SWP_RSVD; + + /* now swapping to this device ok */ + p->pages = j + k; + nr_swap_pages += j; + p->flags = SWP_WRITEOK; + + /* insert swap space into swap_list */ + prev = -1; + for (i = swap_list.head; i >= 0; i = swap_info[i].next) { + if (p->prio >= swap_info[i].prio) { + break; + } + prev = i; + } + p->next = i; + if (prev < 0) { + swap_list.head = swap_list.next = p - swap_info; + } else { + swap_info[prev].next = p - swap_info; + } + + printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n", + p->pages << 2, p->pages ); + return( 1 ); +} + + +/* + * The swap entry has been read in advance, and we return 1 to indicate + * that the page has been used or is no longer needed. + */ +static inline int unswap_pte( struct vm_area_struct * vma, unsigned long + address, pte_t *dir, unsigned long entry, + unsigned long page, int isswap ) +{ + pte_t pte = *dir; + + if (pte_none(pte)) + return 0; + if (pte_present(pte)) { + struct page *pg; + unsigned long page_nr = MAP_NR(pte_page(pte)); + unsigned long pg_swap_entry; + + if (page_nr >= max_mapnr) + return 0; + pg = mem_map + page_nr; + if (!(pg_swap_entry = in_swap_cache(pg))) + return 0; + if (pg_swap_entry != entry) + return 0; + if (isswap) { + DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; " + "exchanging to %08lx\n", + page_address(pg), entry, page ); + pg->offset = page; + swap_free(entry); + return 1; + } + else { + DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; " + "deleted there\n", page_address(pg), entry ); + delete_from_swap_cache(pg); + set_pte(dir, pte_mkdirty(pte)); + free_page(page); + return 1; + } + } + if (pte_val(pte) != entry) + return 0; + + if (isswap) { + DPRINTK( "unswap_pte: replacing entry %08lx by %08lx", entry, page ); + set_pte(dir, __pte(page)); } else { - /* Get memory from rsvd_stram_beg */ - if (rsvd_stram_end + size < stram_end) { - adr = (void *) rsvd_stram_end; - rsvd_stram_end += size; + DPRINTK( "unswap_pte: replacing entry %08lx by new page %08lx", + entry, page ); + set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page,vma->vm_page_prot)))); + ++vma->vm_mm->rss; + } + swap_free(entry); + return 1; +} + +static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, + unsigned long offset, unsigned long entry, + unsigned long page, int isswap ) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*dir)) + return 0; + if (pmd_bad(*dir)) { + printk("unswap_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); + pmd_clear(dir); + return 0; + } + pte = pte_offset(dir, address); + offset += address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (unswap_pte( vma, offset+address-vma->vm_start, pte, entry, + page, isswap )) + return 1; + address += PAGE_SIZE; + pte++; + } while (address < end); + return 0; +} + +static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned long entry, unsigned long page, + int isswap ) +{ + pmd_t * pmd; + unsigned long offset, end; + + if (pgd_none(*dir)) + return 0; + if (pgd_bad(*dir)) { + printk("unswap_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); + pgd_clear(dir); + return 0; + } + pmd = pmd_offset(dir, address); + offset = address & PGDIR_MASK; + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + if (unswap_pmd( vma, pmd, address, end - address, offset, entry, + page, isswap )) + return 1; + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, + unsigned long entry, unsigned long page, int isswap ) +{ + unsigned long start = vma->vm_start, end = vma->vm_end; + + while( start < end ) { + if (unswap_pgd( vma, pgdir, start, end - start, entry, page, isswap )) + return 1; + start = (start + PGDIR_SIZE) & PGDIR_MASK; + pgdir++; + } + return 0; +} + +static int unswap_process( struct mm_struct * mm, unsigned long entry, + unsigned long page, int isswap ) +{ + struct vm_area_struct* vma; + + /* + * Go through process' page directory. + */ + if (!mm || mm == &init_mm) + return 0; + for( vma = mm->mmap; vma; vma = vma->vm_next ) { + pgd_t * pgd = pgd_offset(mm, vma->vm_start); + if (unswap_vma( vma, pgd, entry, page, isswap )) + return 1; + } + return 0; +} + + +static int unswap_by_move( unsigned char *map, unsigned long max, + unsigned long start, unsigned long n_pages ) +{ + struct task_struct *p; + unsigned long entry, rover = (start == 1) ? n_pages+1 : 1; + unsigned long i, j; + + DPRINTK( "unswapping %lu..%lu by moving in swap\n", + start, start+n_pages-1 ); + + /* can free the allocated pages by moving them to other swap pages */ + for( i = start; i < start+n_pages; ++i ) { + if (!map[i]) { + map[i] = SWP_RSVD; + DPRINTK( "unswap: page %lu was free\n", i ); + continue; + } + else if (map[i] == SWP_RSVD) { + printk( KERN_ERR "get_stram_region: page %lu already " + "reserved??\n", i ); + } + DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] ); + + /* find a free page not in our region */ + for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) { + if (j >= start && j < start+n_pages) + continue; + if (!map[j]) { + rover = j+1; + break; + } + } + if (j == rover-1) { + printk( KERN_ERR "get_stram_region: not enough free swap " + "pages now??\n" ); + return( -ENOMEM ); + } + DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", + i, map[i], j, map[j], nr_swap_pages ); + + --nr_swap_pages; + entry = SWP_ENTRY( stram_swap_type, j ); + if (stram_swap_info->lowest_bit == j) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == j) + stram_swap_info->highest_bit--; + + memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE ); +#ifdef DO_PROC + stat_swap_move++; +#endif + + while( map[i] ) { + for_each_task(p) { + if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ), + entry, 1 )) { + map[j]++; + goto repeat; + } + } + if (map[i] && map[i] != 127) { + printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu " + "not used by any process\n", i ); + /* quit while loop and overwrite bad map entry */ + break; + } + else if (!map[i]) { + /* somebody else must have swapped in that page, so free the + * new one (we're moving to) */ + DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" ); + map[j] = 0; + } + repeat: + } + + DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", + i, map[i], j, map[j], nr_swap_pages ); + map[i] = SWP_RSVD; + if (stram_swap_info->lowest_bit == i) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == i) + stram_swap_info->highest_bit--; + --nr_swap_pages; + } + return( 0 ); +} + +static int unswap_by_read( unsigned char *map, unsigned long max, + unsigned long start, unsigned long n_pages ) +{ + struct task_struct *p; + unsigned long entry, page = 0; + unsigned long i; + + DPRINTK( "unswapping %lu..%lu by reading in\n", + start, start+n_pages-1 ); + + for( i = start; i < start+n_pages; ++i ) { + if (map[i] == SWP_RSVD) { + printk( KERN_ERR "get_stram_region: page %lu already " + "reserved??\n", i ); + continue; + } + entry = SWP_ENTRY( stram_swap_type, i ); + DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", + i, map[i], nr_swap_pages ); + + while( map[i] ) { + if (!page && !(page = __get_free_page(GFP_KERNEL))) { + printk( KERN_NOTICE "get_stram_region: out of memory\n" ); + return( -ENOMEM ); + } + DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page ); + read_swap_page( entry, (char *)page ); + + for_each_task(p) { + if (unswap_process( p->mm, entry, page, 0 )) { + page = 0; +#ifdef DO_PROC + stat_swap_force++; +#endif + break; + } + } + if (page) { + /* + * If we couldn't find an entry, there are several + * possible reasons: someone else freed it first, + * we freed the last reference to an overflowed entry, + * or the system has lost track of the use counts. + */ + if (map[i] && map[i] != SWP_RSVD-1) + printk( KERN_ERR "get_stram_region: swap entry %08lx " + "not used by any process\n", entry ); + /* quit while loop and overwrite bad map entry */ + if (!map[i]) { + DPRINTK( "unswap: map[i] became 0\n" ); + } + break; + } + } + + DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", + i, map[i], nr_swap_pages ); + map[i] = SWP_RSVD; + if (stram_swap_info->lowest_bit == i) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == i) + stram_swap_info->highest_bit--; + --nr_swap_pages; + } + + if (page) + free_page(page); + return( 0 ); +} + +/* + * reserve a region in ST-RAM swap space for an allocation + */ +static void *get_stram_region( unsigned long n_pages ) +{ + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned long start, total_free, region_free; + int err; + void *ret = NULL; + + DPRINTK( "get_stram_region(n_pages=%lu)\n", n_pages ); + + /* disallow writing to the swap device now */ + stram_swap_info->flags = SWP_USED; + + /* find a region of n_pages pages in the swap space including as much free + * pages as possible (and excluding any already-reserved pages). */ + if (!(start = find_free_region( n_pages, &total_free, ®ion_free ))) + goto end; + DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n", + start, region_free ); + + err = ((total_free-region_free >= n_pages-region_free) ? + unswap_by_move( map, max, start, n_pages ) : + unswap_by_read( map, max, start, n_pages )); + if (err) + goto end; + + ret = SWAP_ADDR(start); + end: + /* allow using swap device again */ + stram_swap_info->flags = SWP_WRITEOK; + DPRINTK( "get_stram_region: returning %p\n", ret ); + return( ret ); +} + + +/* + * free a reserved region in ST-RAM swap space + */ +static void free_stram_region( unsigned long offset, unsigned long n_pages ) +{ + unsigned char *map = stram_swap_info->swap_map; + + DPRINTK( "free_stram_region(offset=%lu,n_pages=%lu)\n", offset, n_pages ); + + if (offset < 1 || offset + n_pages > stram_swap_info->max) { + printk( KERN_ERR "free_stram_region: Trying to free non-ST-RAM\n" ); + return; + } + + /* un-reserve the freed pages */ + for( ; n_pages > 0; ++offset, --n_pages ) { + if (map[offset] != SWP_RSVD) + printk( KERN_ERR "free_stram_region: Swap page %lu was not " + "reserved\n", offset ); + map[offset] = 0; + } + + /* update swapping meta-data */ + if (offset < stram_swap_info->lowest_bit) + stram_swap_info->lowest_bit = offset; + if (offset+n_pages-1 > stram_swap_info->highest_bit) + stram_swap_info->highest_bit = offset+n_pages-1; + if (stram_swap_info->prio > swap_info[swap_list.next].prio) + swap_list.next = swap_list.head; + nr_swap_pages += n_pages; +} + + +/* ------------------------------------------------------------------------ */ +/* Utility Functions for Swapping */ +/* ------------------------------------------------------------------------ */ + + +/* is addr in some of the allocated regions? */ +static int in_some_region( unsigned long addr ) +{ + BLOCK *p; + + for( p = alloc_list; p; p = p->next ) { + if (p->start <= addr && addr < p->start + p->size) + return( 1 ); + } + return( 0 ); +} + + +static unsigned long find_free_region( unsigned long n_pages, + unsigned long *total_free, + unsigned long *region_free ) +{ + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned long head, tail, max_start; + long nfree, max_free; + + /* first scan the swap space for a suitable place for the allocation */ + head = 1; + max_start = 0; + max_free = -1; + *total_free = 0; + + start_over: + /* increment tail until final window size reached, and count free pages */ + nfree = 0; + for( tail = head; tail-head < n_pages && tail < max-n_pages; ++tail ) { + if (map[tail] == SWP_RSVD) { + head = tail+1; + goto start_over; + } + if (!map[tail]) { + ++nfree; + ++*total_free; } } + if (tail-head < n_pages) + goto out; + if (nfree > max_free) { + max_start = head; + max_free = nfree; + if (max_free >= n_pages) + /* don't need more free pages... :-) */ + goto out; + } - return( adr ); + /* now shift the window and look for the area where as much pages as + * possible are free */ + while( tail < max ) { + nfree -= (map[head++] == 0); + if (map[tail] == SWP_RSVD) { + head = tail+1; + goto start_over; + } + if (!map[tail]) { + ++nfree; + ++*total_free; + } + ++tail; + if (nfree > max_free) { + max_start = head; + max_free = nfree; + if (max_free >= n_pages) + /* don't need more free pages... :-) */ + goto out; + } + } + + out: + if (max_free < 0) { + printk( KERN_NOTICE "get_stram_region: ST-RAM too full or fragmented " + "-- can't allocate %lu pages\n", n_pages ); + return( 0 ); + } + + *region_free = max_free; + return( max_start ); } -void atari_stram_free( void *ptr ) +/* setup parameters from command line */ +void stram_swap_setup( char *str, int *ints ) { - /* Sorry, this is a dummy. It isn't needed anyway. */ + if (ints[0] >= 1) + max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK; } + +/* ------------------------------------------------------------------------ */ +/* ST-RAM device */ +/* ------------------------------------------------------------------------ */ + +static int stram_blocksizes[14] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096 }; +static int stram_sizes[14] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static int refcnt = 0; + +static void do_stram_request( void ) +{ + unsigned long start, len; + + while( CURRENT ) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic("stram: request list destroyed"); + if (CURRENT->bh) { + if (!buffer_locked(CURRENT->bh)) + panic("stram: block not locked"); + } + + start = swap_start + (CURRENT->sector << 9); + len = CURRENT->current_nr_sectors << 9; + if ((start + len) > swap_end) { + printk( KERN_ERR "stram: bad access beyond end of device: " + "block=%ld, count=%ld\n", + CURRENT->sector, + CURRENT->current_nr_sectors ); + end_request( 0 ); + continue; + } + + if (CURRENT->cmd == READ) { + memcpy( CURRENT->buffer, (char *)start, len ); +#ifdef DO_PROC + stat_swap_read += N_PAGES(len); #endif + } + else { + memcpy( (char *)start, CURRENT->buffer, len ); +#ifdef DO_PROC + stat_swap_write += N_PAGES(len); +#endif + } + end_request( 1 ); + } +} +static int stram_open( struct inode *inode, struct file *filp ) +{ + if (filp != MAGIC_FILE_P) { + printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" ); + return( -EPERM ); + } + if (MINOR(inode->i_rdev) != STRAM_MINOR) + return( -ENXIO ); + if (refcnt) + return( -EBUSY ); + ++refcnt; + return( 0 ); +} + +static int stram_release( struct inode *inode, struct file *filp ) +{ + if (filp != MAGIC_FILE_P) { + printk( KERN_NOTICE "Only kernel can close ST-RAM device\n" ); + return( -EPERM ); + } + if (refcnt > 0) + --refcnt; + return( 0 ); +} + + +static struct file_operations stram_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + stram_open, /* open */ + stram_release, /* release */ + block_fsync /* fsync */ +}; + +int stram_device_init( void ) +{ + + if (!MACH_IS_ATARI) + /* no point in initializing this, I hope */ + return( -ENXIO ); + + if (!max_swap_size) + /* swapping not enabled */ + return( -ENXIO ); + + if (register_blkdev( STRAM_MAJOR, "stram", &stram_fops)) { + printk( KERN_ERR "stram: Unable to get major %d\n", STRAM_MAJOR ); + return( -ENXIO ); + } + + blk_dev[STRAM_MAJOR].request_fn = do_stram_request; + blksize_size[STRAM_MAJOR] = stram_blocksizes; + stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024; + blk_size[STRAM_MAJOR] = stram_sizes; + do_z2_request(); /* to avoid warning */ + return( 0 ); +} + +/* to avoid warning */ +static void do_z2_request( void ) { } + +#endif /* CONFIG_STRAM_SWAP */ + + +/* ------------------------------------------------------------------------ */ +/* Misc Utility Functions */ +/* ------------------------------------------------------------------------ */ + + +/* return log2 of #pages for size */ +static int get_gfp_order( unsigned long size ) +{ + int order; + + size = N_PAGES( size + PAGE_SIZE -1 ); + order = -1; + do { + size >>= 1; + order++; + } while (size); + + return( order ); +} + + +/* reserve a range of pages in mem_map[] */ +static void reserve_region( unsigned long addr, unsigned long end ) +{ + mem_map_t *mapp = &mem_map[MAP_NR(addr)]; + + for( ; addr < end; addr += PAGE_SIZE, ++mapp ) + set_bit( PG_reserved, &mapp->flags ); +} + + + +/* ------------------------------------------------------------------------ */ +/* Region Management */ +/* ------------------------------------------------------------------------ */ + + +/* insert a region into the alloced list (sorted) */ +static BLOCK *add_region( void *addr, unsigned long size ) +{ + BLOCK **p, *n = NULL; + int i; + + for( i = 0; i < N_STATIC_BLOCKS; ++i ) { + if (static_blocks[i].flags & BLOCK_FREE) { + n = &static_blocks[i]; + n->flags = 0; + break; + } + } + if (!n && mem_init_done) { + /* if statics block pool exhausted and we can call kmalloc() already + * (after mem_init()), try that */ + n = kmalloc( sizeof(BLOCK), GFP_KERNEL ); + if (n) + n->flags = BLOCK_KMALLOCED; + } + if (!n) { + printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" ); + return( NULL ); + } + n->start = (unsigned long)addr; + n->size = size; + + for( p = &alloc_list; *p; p = &((*p)->next) ) + if ((*p)->start > (unsigned long)addr) break; + n->next = *p; + *p = n; + + return( n ); +} + + +/* find a region (by start addr) in the alloced list */ +static BLOCK *find_region( void *addr ) +{ + BLOCK *p; + + for( p = alloc_list; p; p = p->next ) { + if (p->start == (unsigned long)addr) + return( p ); + if (p->start > (unsigned long)addr) + break; + } + return( NULL ); +} + + +/* remove a block from the alloced list */ +static int remove_region( BLOCK *block ) +{ + BLOCK **p; + + for( p = &alloc_list; *p; p = &((*p)->next) ) + if (*p == block) break; + if (!*p) + return( 0 ); + + *p = block->next; + if (block->flags & BLOCK_KMALLOCED) + kfree( block ); + else + block->flags |= BLOCK_FREE; + return( 1 ); +} + + + +/* ------------------------------------------------------------------------ */ +/* /proc statistics file stuff */ +/* ------------------------------------------------------------------------ */ + +#ifdef DO_PROC + +#define PRINT_PROC(fmt,args...) len += sprintf( buf+len, fmt, ##args ) + +int get_stram_list( char *buf ) +{ + int len = 0; + BLOCK *p; +#ifdef CONFIG_STRAM_SWAP + int i; + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned free = 0, used = 0, rsvd = 0; +#endif + +#ifdef CONFIG_STRAM_SWAP + if (max_swap_size) { + for( i = 1; i < max; ++i ) { + if (!map[i]) + ++free; + else if (map[i] == SWP_RSVD) + ++rsvd; + else + ++used; + } + PRINT_PROC( + "Total ST-RAM: %8lu kB\n" + "Total ST-RAM swap: %8lu kB\n" + "Free swap: %8u kB\n" + "Used swap: %8u kB\n" + "Allocated swap: %8u kB\n" + "Swap Reads: %8u\n" + "Swap Writes: %8u\n" + "Swap Moves: %8u\n" + "Swap Forced Reads: %8u\n", + (stram_end - stram_start) >> 10, + (max-1) << (PAGE_SHIFT-10), + free << (PAGE_SHIFT-10), + used << (PAGE_SHIFT-10), + rsvd << (PAGE_SHIFT-10), + stat_swap_read, + stat_swap_write, + stat_swap_move, + stat_swap_force ); + } + else { +#endif + PRINT_PROC( "ST-RAM swapping disabled\n" ); + PRINT_PROC( + "Total ST-RAM: %8lu kB\n" + "Reserved ST-RAM: %8lu kB\n", + (stram_end - stram_start) >> 10, + (rsvd_stram_end - rsvd_stram_beg) >> 10 ); +#ifdef CONFIG_STRAM_SWAP + } +#endif + + PRINT_PROC( "Allocated regions:\n" ); + for( p = alloc_list; p; p = p->next ) { + if (len + 50 >= PAGE_SIZE) + break; + PRINT_PROC( "0x%08lx-0x%08lx: %s (", + VTOP(p->start), VTOP(p->start+p->size-1), p->owner ); + if (p->flags & BLOCK_STATIC) + PRINT_PROC( "static)\n" ); + else if (p->flags & BLOCK_GFP) + PRINT_PROC( "page-alloced)\n" ); + else if (p->flags & BLOCK_INSWAP) + PRINT_PROC( "in swap)\n" ); + else + PRINT_PROC( "??)\n" ); + } + + return( len ); +} + +#endif + + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c --- v2.1.86/linux/arch/m68k/atari/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/atari/time.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,416 @@ +/* + * linux/arch/m68k/atari/time.c + * + * Atari time and real time clock stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * 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 + + +__initfunc(void +atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) +{ + /* set Timer C data Register */ + mfp.tim_dt_c = INT_TICKS; + /* start timer C, div = 1:100 */ + mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; + /* install interrupt service routine for MFP Timer C */ + request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, + "timer", timer_routine); +} + +/* ++andreas: gettimeoffset fixed to check for pending interrupt */ + +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +unsigned long atari_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read MFP timer C current value */ + ticks = mfp.tim_dt_c; + /* The probability of underflow is less than 2% */ + if (ticks > INT_TICKS - INT_TICKS / 50) + /* Check for pending timer interrupt */ + if (mfp.int_pn_b & (1 << 5)) + offset = TICK_SIZE; + + ticks = INT_TICKS - ticks; + ticks = ticks * 10000L / INT_TICKS; + + return ticks + offset; +} + + +static void mste_read(struct MSTE_RTC *val) +{ +#define COPY(v) val->v=(mste_rtc.v & 0xf) + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from reading the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +static void mste_write(struct MSTE_RTC *val) +{ +#define COPY(v) mste_rtc.v=val->v + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from writing the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +#define RTC_READ(reg) \ + ({ unsigned char __val; \ + outb(reg,&tt_rtc.regsel); \ + __val = tt_rtc.data; \ + __val; \ + }) + +#define RTC_WRITE(reg,val) \ + do { \ + outb(reg,&tt_rtc.regsel); \ + tt_rtc.data = (val); \ + } while(0) + + +void atari_mste_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + int hr24=0, hour; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + mste_read(&val); + *secp = val.sec_ones + val.sec_tens * 10; + *minp = val.min_ones + val.min_tens * 10; + hour = val.hr_ones + val.hr_tens * 10; + if (!hr24) { + if (hour == 12 || hour == 12 + 20) + hour -= 12; + if (hour >= 20) + hour += 12 - 20; + } + *hourp = hour; + *dayp = val.day_ones + val.day_tens * 10; + *monp = val.mon_ones + val.mon_tens * 10; + *yearp = val.year_ones + val.year_tens * 10 + 80; +} + + +void atari_tt_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + unsigned char ctrl; + int hour, pm; + + while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; + while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; + + *secp = RTC_READ(RTC_SECONDS); + *minp = RTC_READ(RTC_MINUTES); + hour = RTC_READ(RTC_HOURS); + *dayp = RTC_READ(RTC_DAY_OF_MONTH); + *monp = RTC_READ(RTC_MONTH); + *yearp = RTC_READ(RTC_YEAR); + pm = hour & 0x80; + hour &= ~0x80; + + ctrl = RTC_READ(RTC_CONTROL); + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(*secp); + BCD_TO_BIN(*minp); + BCD_TO_BIN(hour); + BCD_TO_BIN(*dayp); + BCD_TO_BIN(*monp); + BCD_TO_BIN(*yearp); + } + if (!(ctrl & RTC_24H)) { + if (!pm && hour == 12) + hour = 0; + else if (pm && hour != 12) + hour += 12; + } + *hourp = hour; + + /* Adjust values (let the setup valid) */ + *yearp += atari_rtc_year_offset; +} + +#define HWCLK_POLL_INTERVAL 5 + +int atari_mste_hwclk( int op, struct hwclk_time *t ) +{ + int hour, year; + int hr24=0; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + if (op) { + /* write: prepare values */ + + val.sec_ones = t->sec % 10; + val.sec_tens = t->sec / 10; + val.min_ones = t->min % 10; + val.min_tens = t->min / 10; + hour = t->hour; + if (!hr24) { + if (hour > 11) + hour += 20 - 12; + if (hour == 0 || hour == 20) + hour += 12; + } + val.hr_ones = hour % 10; + val.hr_tens = hour / 10; + val.day_ones = t->day % 10; + val.day_tens = t->day / 10; + val.mon_ones = (t->mon+1) % 10; + val.mon_tens = (t->mon+1) / 10; + year = t->year - 80; + val.year_ones = year % 10; + val.year_tens = year / 10; + val.weekday = t->wday; + mste_write(&val); + mste_rtc.mode=(mste_rtc.mode | 1); + val.year_ones = (year % 4); /* leap year register */ + mste_rtc.mode=(mste_rtc.mode & ~1); + } + else { + mste_read(&val); + t->sec = val.sec_ones + val.sec_tens * 10; + t->min = val.min_ones + val.min_tens * 10; + hour = val.hr_ones + val.hr_tens * 10; + if (!hr24) { + if (hour == 12 || hour == 12 + 20) + hour -= 12; + if (hour >= 20) + hour += 12 - 20; + } + t->hour = hour; + t->day = val.day_ones + val.day_tens * 10; + t->mon = val.mon_ones + val.mon_tens * 10 - 1; + t->year = val.year_ones + val.year_tens * 10 + 80; + t->wday = val.weekday; + } + return 0; +} + +int atari_tt_hwclk( int op, struct hwclk_time *t ) +{ + int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; + unsigned long flags; + unsigned char ctrl; + int pm = 0; + + ctrl = RTC_READ(RTC_CONTROL); /* control registers are + * independent from the UIP */ + + if (op) { + /* write: prepare values */ + + sec = t->sec; + min = t->min; + hour = t->hour; + day = t->day; + mon = t->mon + 1; + year = t->year - atari_rtc_year_offset; + wday = t->wday + (t->wday >= 0); + + if (!(ctrl & RTC_24H)) { + if (hour > 11) { + pm = 0x80; + if (hour != 12) + hour -= 12; + } + else if (hour == 0) + hour = 12; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hour); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(year); + if (wday >= 0) BIN_TO_BCD(wday); + } + } + + /* Reading/writing the clock registers is a bit critical due to + * the regular update cycle of the RTC. While an update is in + * progress, registers 0..9 shouldn't be touched. + * The problem is solved like that: If an update is currently in + * progress (the UIP bit is set), the process sleeps for a while + * (50ms). This really should be enough, since the update cycle + * normally needs 2 ms. + * If the UIP bit reads as 0, we have at least 244 usecs until the + * update starts. This should be enough... But to be sure, + * additionally the RTC_SET bit is set to prevent an update cycle. + */ + + while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HWCLK_POLL_INTERVAL; + schedule(); + } + + save_flags(flags); + cli(); + RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); + if (!op) { + sec = RTC_READ( RTC_SECONDS ); + min = RTC_READ( RTC_MINUTES ); + hour = RTC_READ( RTC_HOURS ); + day = RTC_READ( RTC_DAY_OF_MONTH ); + mon = RTC_READ( RTC_MONTH ); + year = RTC_READ( RTC_YEAR ); + wday = RTC_READ( RTC_DAY_OF_WEEK ); + } + else { + RTC_WRITE( RTC_SECONDS, sec ); + RTC_WRITE( RTC_MINUTES, min ); + RTC_WRITE( RTC_HOURS, hour + pm); + RTC_WRITE( RTC_DAY_OF_MONTH, day ); + RTC_WRITE( RTC_MONTH, mon ); + RTC_WRITE( RTC_YEAR, year ); + if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); + } + RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); + restore_flags(flags); + + if (!op) { + /* read: adjust values */ + + if (hour & 0x80) { + hour &= ~0x80; + pm = 1; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(wday); + } + + if (!(ctrl & RTC_24H)) { + if (!pm && hour == 12) + hour = 0; + else if (pm && hour != 12) + hour += 12; + } + + t->sec = sec; + t->min = min; + t->hour = hour; + t->day = day; + t->mon = mon - 1; + t->year = year + atari_rtc_year_offset; + t->wday = wday - 1; + } + + return( 0 ); +} + + +int atari_mste_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + struct MSTE_RTC val; + unsigned char rtc_minutes; + + mste_read(&val); + rtc_minutes= val.min_ones + val.min_tens * 10; + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + val.sec_ones = real_seconds % 10; + val.sec_tens = real_seconds / 10; + val.min_ones = real_minutes % 10; + val.min_tens = real_minutes / 10; + mste_write(&val); + } + else + return -1; + return 0; +} + +int atari_tt_set_clock_mmss (unsigned long nowtime) +{ + int retval = 0; + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + unsigned char save_control, save_freq_select, rtc_minutes; + + save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ + RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); + + save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); + + rtc_minutes = RTC_READ (RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY)) + BCD_TO_BIN (rtc_minutes); + + /* Since we're only adjusting minutes and seconds, don't interfere + with hour overflow. This avoids messing with unknown time zones + but requires your RTC not to be off by more than 30 minutes. */ + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + if (!(save_control & RTC_DM_BINARY)) + { + BIN_TO_BCD (real_seconds); + BIN_TO_BCD (real_minutes); + } + RTC_WRITE (RTC_SECONDS, real_seconds); + RTC_WRITE (RTC_MINUTES, real_minutes); + } + else + retval = -1; + + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); + RTC_WRITE (RTC_CONTROL, save_control); + return retval; +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.1.86/linux/arch/m68k/config.in Thu Feb 12 20:56:04 1998 +++ linux/arch/m68k/config.in Thu Feb 12 16:30:12 1998 @@ -23,7 +23,19 @@ bool 'Amiga support' CONFIG_AMIGA bool 'Atari support' CONFIG_ATARI +if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Hades support' CONFIG_HADES + if [ "$CONFIG_HADES" = "y" ]; then + define_bool CONFIG_PCI y + fi +fi bool 'Macintosh support' CONFIG_MAC +bool 'Apollo support' CONFIG_APOLLO +bool 'VME (Motorola and BVM) support' CONFIG_VME +if [ "$CONFIG_VME" = "y" ]; then + bool 'MVME162, 166 and 167 support' CONFIG_MVME16x +# bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000 +fi comment 'Processor type' bool '68020 support' CONFIG_M68020 @@ -56,19 +68,19 @@ if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga AutoConfig Identification' CONFIG_ZORRO - bool 'Amiga OCS chipset support' CONFIG_AMIFB_OCS - bool 'Amiga ECS chipset support' CONFIG_AMIFB_ECS - bool 'Amiga AGA chipset support' CONFIG_AMIFB_AGA - bool 'Amiga Cybervision support' CONFIG_FB_CYBER - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 - fi # bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP # if [ "$CONFIG_AMIGA_GSP" = "y" ]; then # bool 'DMI Resolver support' CONFIG_GSP_RESOLVER # bool 'A2410 support' CONFIG_GSP_A2410 # fi fi +if [ "$CONFIG_ATARI" = "y" ]; then + bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP + bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC +fi +if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then + bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT +fi endmenu # @@ -77,7 +89,17 @@ mainmenu_option next_comment comment 'Floppy, IDE, and other block devices' -tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD +if [ "$CONFIG_AMIGA" = "y" ]; then + tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY +fi +if [ "$CONFIG_MAC" = "y" ]; then + tristate 'Macintosh IWM floppy support' CONFIG_MAC_FLOPPY +fi +#Normal floppy disk support' CONFIG_BLK_DEV_FD + tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE @@ -85,6 +107,16 @@ dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA + bool ' Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE + fi + fi + if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE + fi fi if [ "$CONFIG_AMIGA" = "y" ]; then tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM @@ -138,6 +170,7 @@ bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS +bool 'SCSI logging facility' CONFIG_SCSI_LOGGING mainmenu_option next_comment comment 'SCSI low-level drivers' @@ -155,14 +188,26 @@ bool 'A4000T SCSI support' CONFIG_A4000T_SCSI bool 'A4091 SCSI support' CONFIG_A4091_SCSI bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI - bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI + bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI +# bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI fi fi if [ "$CONFIG_ATARI" = "y" ]; then dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then + bool 'Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL + fi +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI + +if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then + bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI +fi + endmenu fi @@ -195,12 +240,21 @@ tristate 'A2065 support' CONFIG_A2065 tristate 'Hydra support' CONFIG_HYDRA fi +if [ "$CONFIG_APOLLO" = "y" ] ; then + tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS +fi if [ "$CONFIG_ATARI" = "y" ]; then - bool 'Atari Lance support' CONFIG_ATARILANCE -if [ "$CONFIG_ATARI_ACSI" = "y" ]; then - bool 'BioNet-100 support' CONFIG_ATARI_BIONET - bool 'PAMsNet support' CONFIG_ATARI_PAMSNET + tristate 'Atari Lance support' CONFIG_ATARILANCE + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + tristate 'BioNet-100 support' CONFIG_ATARI_BIONET + tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET + fi +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT fi +if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then + bool 'MVME16x Ethernet support' CONFIG_APRICOT fi fi endmenu @@ -220,14 +274,23 @@ source fs/Config.in +if [ "$CONFIG_VME" = "n" ]; then + define_bool CONFIG_FB y + source drivers/video/Config.in +fi + source fs/nls/Config.in mainmenu_option next_comment comment 'Character devices' - -define_bool CONFIG_VT y -define_bool CONFIG_VT_CONSOLE y -define_bool CONFIG_FB_CONSOLE y + +if [ "$CONFIG_VME" = "n" ]; then + define_bool CONFIG_VT y + if [ "$CONFIG_VT" = "y" ]; then + bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE + fi + define_bool CONFIG_FB_CONSOLE y +fi if [ "$CONFIG_ATARI" = "y" ]; then define_bool CONFIG_NVRAM y @@ -241,6 +304,9 @@ if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari mouse support' CONFIG_ATARIMOUSE fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'Mac ADB mouse support' CONFIG_MACMOUSE +fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER tristate 'Atari SCC serial support' CONFIG_ATARI_SCC @@ -260,11 +326,25 @@ tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET fi -if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ - "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ - "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then - bool 'Serial console support' CONFIG_SERIAL_CONSOLE +if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then + if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ + "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ + "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then + bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE + fi +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'Mac SCC serial support' CONFIG_MAC_SCC fi +if [ "$CONFIG_VME" = "y" ]; then + define_bool CONFIG_SERIAL_CONSOLE y + bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167 + bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC +fi +if [ "$CONFIG_APOLLO" = "y" ]; then + bool 'Support for DN serial port (dummy)' CONFIG_SERIAL + bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE +fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then @@ -274,6 +354,9 @@ bool 'Support for user misc device modules' CONFIG_UMISC if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then define_bool CONFIG_ABSTRACT_CONSOLE y +fi +if [ "$CONFIG_ATARI" = "y" ]; then + bool 'Enhanced Real Time Clock Support' CONFIG_RTC fi endmenu diff -u --recursive --new-file v2.1.86/linux/arch/m68k/defconfig linux/arch/m68k/defconfig --- v2.1.86/linux/arch/m68k/defconfig Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/defconfig Thu Feb 12 16:30:12 1998 @@ -42,11 +42,6 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_ZORRO=y -CONFIG_AMIFB_OCS=y -CONFIG_AMIFB_ECS=y -CONFIG_AMIFB_AGA=y -# CONFIG_FB_CYBER is not set -# CONFIG_FB_RETINAZ3 is not set # CONFIG_AMIGA_GSP is not set # CONFIG_GSP_RESOLVER is not set # CONFIG_GSP_A2410 is not set @@ -54,7 +49,8 @@ # # Block device driver configuration # -CONFIG_BLK_DEV_FD=y +CONFIG_AMIGA_FLOPPY=y +CONFIG_ATARI_FLOPPY=y # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_IDE is not set # CONFIG_BLK_DEV_IDEDISK is not set @@ -62,6 +58,7 @@ # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_IDEDOUBLER is not set # CONFIG_AMIGA_Z2RAM is not set # CONFIG_ATARI_ACSI is not set # CONFIG_ACSI_MULTI_LUN is not set @@ -132,6 +129,9 @@ # CONFIG_BLZ2060_SCSI is not set # CONFIG_BLZ1230_SCSI is not set # CONFIG_FASTLANE_SCSI is not set +# CONFIG_A4000T_SCSI is not set +# CONFIG_A4091_SCSI is not set +# CONFIG_WARPENGINE_SCSI is not set CONFIG_ATARI_SCSI=y # @@ -169,6 +169,21 @@ # CONFIG_AFFS_FS is not set # CONFIG_ROMFS_FS is not set # CONFIG_UFS_FS is not set + +# +# Frame buffer devices +# +CONFIG_FB_AMIGA=y +CONFIG_FB_AMIGA_OCS=y +CONFIG_FB_AMIGA_ECS=y +CONFIG_FB_AMIGA_AGA=y +# CONFIG_FB_CYBER is not set +# CONFIG_FB_RETINAZ3 is not set +# CONFIG_FB_ATARI is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set + +CONFIG_NLS_CODEPAGE_437=y # # Character devices diff -u --recursive --new-file v2.1.86/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S --- v2.1.86/linux/arch/m68k/ifpsp060/iskeleton.S Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/ifpsp060/iskeleton.S Thu Feb 12 16:30:12 1998 @@ -183,7 +183,7 @@ | | _060_lock_page(): | -| Entry point for the operating system's routine to "lock" a page +| Entry point for the operating system`s routine to "lock" a page | from being paged out. This routine is needed by the cas/cas2 | algorithms so that no page faults occur within the "core" code | region. Note: the routine must lock two pages if the operand @@ -208,7 +208,7 @@ | | _060_unlock_page(): | -| Entry point for the operating system's routine to "unlock" a +| Entry point for the operating system`s routine to "unlock" a | page that has been "locked" previously with _real_lock_page. | Note: the routine must unlock two pages if the operand spans | two pages. diff -u --recursive --new-file v2.1.86/linux/arch/m68k/ifpsp060/os.S linux/arch/m68k/ifpsp060/os.S --- v2.1.86/linux/arch/m68k/ifpsp060/os.S Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/ifpsp060/os.S Thu Feb 12 16:30:12 1998 @@ -345,7 +345,6 @@ copyinae: movs.b (%a0)+,%d1 | fetch user byte move.b %d1,(%a1)+ | write supervisor byte - subq.l #0x1,%d0 | are we through yet? dbra %d0,morein | are we through yet? moveq #0,%d0 | return success rts diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile --- v2.1.86/linux/arch/m68k/kernel/Makefile Sat Aug 16 09:51:07 1997 +++ linux/arch/m68k/kernel/Makefile Thu Feb 12 16:30:12 1998 @@ -10,19 +10,26 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o -all: kernel.o head.o +all: head.o kernel.o 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 -ifdef CONFIG_VT -O_OBJS += console.o -endif OX_OBJS := m68k_ksyms.o ifdef CONFIG_KGDB O_OBJS += kgdb.o endif -head.o: head.S +ifdef CONFIG_PCI +O_OBJS += bios32.o +endif + +head.o: head.S m68k_defs.h + +m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h + $(CC) ${CFLAGS} -S m68k_defs.c + cp m68k_defs.head m68k_defs.h + sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p' + rm m68k_defs.s include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c --- v2.1.86/linux/arch/m68k/kernel/bios32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/kernel/bios32.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,580 @@ +/* + * bios32.c - PCI BIOS functions for Alpha systems not using BIOS + * emulation code. + * + * Written by Wout Klaren. + * + * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger. + */ + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#ifdef CONFIG_PCI + +/* + * PCI support for Linux/m68k. Currently only the Hades is supported. + * + * Notes: + * + * 1. The PCI memory area starts at address 0x80000000 and the + * I/O area starts at 0xB0000000. Therefore these offsets + * are added to the base addresses when they are read and + * substracted when they are written. + * + * 2. The support for PCI bridges in the DEC Alpha version has + * been removed in this version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define MAJOR_REV 0 +#define MINOR_REV 0 + +/* + * Base addresses of the PCI memory and I/O areas on the Hades. + */ + +static unsigned long pci_mem_base = 0; +static unsigned long pci_io_base = 0; + +/* + * Align VAL to ALIGN, which must be a power of two. + */ + +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) + +/* + * Calculate the address of the PCI configuration area of the given + * device. + * + * BUG: boards with multiple functions are probably not correctly + * supported. + */ + +static int mk_conf_addr(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned long *pci_addr) +{ + static const unsigned long pci_conf_base[] = { 0xA0080000, 0xA0040000, + 0xA0020000, 0xA0010000 }; + int device = device_fn >> 3; + + DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n", + bus, device_fn, where, pci_addr)); + + if (device > 3) { + DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning -1\n", device)); + return -1; + } + + *pci_addr = pci_conf_base[device] | (where); + DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", *pci_addr)); + return 0; +} + +int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned long pci_addr; + + *value = 0xff; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *((unsigned char *)pci_addr); + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_word(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned long pci_addr; + + *value = 0xffff; + + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = le16_to_cpu(*((unsigned short *)pci_addr)); + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_dword(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long pci_addr; + + *value = 0xffffffff; + + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = le32_to_cpu(*((unsigned int *)pci_addr)); + + if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) + { + if ((*value & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_IO) + *value += pci_io_base; + else + { + if (*value == 0) + { + /* + * Base address is 0. Test if this base + * address register is used. + */ + + *((unsigned long *)pci_addr) = 0xffffffff; + if (*((unsigned long *)pci_addr) != 0) + *value += pci_mem_base; + } + else + *value += pci_mem_base; + } + } + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_byte(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + *((unsigned char *)pci_addr) = value; + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_word(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + *((unsigned short *)pci_addr) = cpu_to_le16(value); + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_dword(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) + { + if ((value & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_IO) + value -= pci_io_base; + else + value -= pci_mem_base; + } + + *((unsigned int *)pci_addr) = cpu_to_le32(value); + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Macro to enable programming of the PCI devices. On the Hades this + * define should be true, because the Hades has no PCI BIOS. + */ + +#define PCI_MODIFY 1 + +#if PCI_MODIFY + +/* + * Leave some room for a VGA card. We assume that the VGA card is + * always in the first 32M of PCI memory. For the time being we do + * not program the VGA card, because to make this work we also + * need to change the frame buffer device. + */ + +#define FIRST_IO_ADDR 0x10000 +#define FIRST_MEM_ADDR 0x02000000 + +static unsigned int io_base = FIRST_IO_ADDR; /* Skip first 64K. */ +static unsigned int mem_base = FIRST_MEM_ADDR; /* Skip first 32M. */ + +/* + * Disable PCI device DEV so that it does not respond to I/O or memory + * accesses. + */ + +__initfunc(static void disable_dev(struct pci_dev *dev)) +{ + struct pci_bus *bus; + unsigned short cmd; + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + return; + + bus = dev->bus; + pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + + cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); + pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd); +} + +/* + * Layout memory and I/O for a device: + */ + +#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2) + +__initfunc(static void layout_dev(struct pci_dev *dev)) +{ + struct pci_bus *bus; + unsigned short cmd; + unsigned int base, mask, size, reg; + unsigned int alignto; + + /* + * Skip video cards for the time being. + */ + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + return; + + bus = dev->bus; + pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + + for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) + { + /* + * Figure out how much space and of what type this + * device wants. + */ + + pcibios_write_config_dword(bus->number, dev->devfn, reg, + 0xffffffff); + pcibios_read_config_dword(bus->number, dev->devfn, reg, &base); + + if (!base) + { + /* this base-address register is unused */ + continue; + } + + /* + * We've read the base address register back after + * writing all ones and so now we must decode it. + */ + + if (base & PCI_BASE_ADDRESS_SPACE_IO) + { + /* + * I/O space base address register. + */ + + cmd |= PCI_COMMAND_IO; + + base &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + /* align to multiple of size of minimum base */ + alignto = MAX(0x400, size) ; + base = ALIGN(io_base, alignto); + io_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, + reg, base | 0x1); + DBG_DEVS(("layout_dev: IO address: %lX\n", base)); + } + else + { + unsigned int type; + + /* + * Memory space base address register. + */ + + cmd |= PCI_COMMAND_MEMORY; + type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + switch (type) + { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + + case PCI_BASE_ADDRESS_MEM_TYPE_64: + printk("bios32 WARNING: " + "ignoring 64-bit device in " + "slot %d, function %d: \n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + reg += 4; /* skip extra 4 bytes */ + continue; + + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + printk("bios32 WARNING: slot %d, function %d " + "requests memory below 1MB---don't " + "know how to do that.\n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + continue; + } + + /* + * Align to multiple of size of minimum base + */ + + alignto = MAX(0x1000, size) ; + base = ALIGN(mem_base, alignto); + mem_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, + reg, base); + } + } + + /* + * Enable device: + */ + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || + dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + { + /* + * 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 I/O to these + * devices. + */ + cmd |= PCI_COMMAND_IO; + } + + pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, + cmd | PCI_COMMAND_MASTER); + DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n", + bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); +} + +__initfunc(static void layout_bus(struct pci_bus *bus)) +{ + struct pci_dev *dev; + + DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); + + if (!bus->devices && !bus->children) + return; + + /* + * Align the current bases on appropriate boundaries (4K for + * IO and 1MB for memory). + */ + + io_base = ALIGN(io_base, 4*KB); + mem_base = ALIGN(mem_base, 1*MB); + + /* + * PCI devices might have been setup by a PCI BIOS emulation + * running under TOS. In these cases there is a + * window during which two devices may have an overlapping + * address range. To avoid this causing trouble, we first + * turn off the I/O and memory address decoders for all PCI + * devices. They'll be re-enabled only once all address + * decoders are programmed consistently. + */ + + for (dev = bus->devices; dev; dev = dev->sibling) + { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) + disable_dev(dev); + } + + /* + * Allocate space to each device: + */ + + DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number)); + + for (dev = bus->devices; dev; dev = dev->sibling) + { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) + layout_dev(dev); + } +} + +#endif /* !PCI_MODIFY */ + +/* + * Given the vendor and device ids, find the n'th instance of that device + * in the system. + */ + +int pcibios_find_device(unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + { + if (dev->vendor == vendor && dev->device == device_id) + { + if (curr == index) + { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +/* + * Given the class, find the n'th instance of that device + * in the system. + */ + +int pcibios_find_class(unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + { + if (dev->class == class_code) + { + if (curr == index) + { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +int pcibios_present(void) +{ + if (MACH_IS_HADES) + return 1; + else + return 0; +} + +__initfunc(unsigned long pcibios_init(unsigned long mem_start, + unsigned long mem_end)) +{ + printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); + +#if !PCI_MODIFY + printk("...NOT modifying existing PCI configuration\n"); +#endif + + return mem_start; +} + +/* + * static inline void hades_fixup(void) + * + * Assign IRQ numbers as used by Linux to the interrupt pins + * of the PCI cards. + */ + +__initfunc(static inline void hades_fixup(void)) +{ + char irq_tab[4] = { + IRQ_TT_MFP_IO0, /* Slot 0. */ + IRQ_TT_MFP_IO1, /* Slot 1. */ + IRQ_TT_MFP_SCC, /* Slot 2. */ + IRQ_TT_MFP_SCSIDMA /* Slot 3. */ + }; + struct pci_dev *dev; + unsigned char slot; + + /* + * Go through all devices, fixing up irqs as we see fit: + */ + + for (dev = pci_devices; dev; dev = dev->next) + { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) + { + slot = PCI_SLOT(dev->devfn); /* Determine slot number. */ + dev->irq = irq_tab[slot]; +#if PCI_MODIFY + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, dev->irq); +#endif + } + } +} + +__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, + unsigned long mem_end)) +{ +#if PCI_MODIFY + /* + * Scan the tree, allocating PCI memory and I/O space. + */ + + layout_bus(&pci_root); +#endif + + pci_mem_base = 0x80000000; + pci_io_base = 0xB0000000; + + /* + * Now is the time to do all those dirty little deeds... + */ + + hades_fixup(); + + return mem_start; +} +#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c --- v2.1.86/linux/arch/m68k/kernel/console.c Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/kernel/console.c Wed Dec 31 16:00:00 1969 @@ -1,2748 +0,0 @@ -/* - * linux/drivers/char/console.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ -/* - * console.c - * - * This module exports the console io functions: - * - * 'void do_keyboard_interrupt(void)' - * - * 'int vc_allocate(unsigned int console)' - * 'int vc_cons_allocated(unsigned int console)' - * 'int vc_resize(unsigned long lines, unsigned long cols)' - * 'int vc_resize_con(unsigned long lines, unsigned long cols, - * unsigned int currcons)' - * 'void vc_disallocate(unsigned int currcons)' - * - * 'unsigned long con_init(unsigned long)' - * 'int con_open(struct tty_struct *tty, struct file * filp)' - * 'void con_write(struct tty_struct * tty)' - * 'void vt_console_print(const char * b)' - * 'void update_screen(int new_console)' - * - * 'void do_blank_screen(int)' - * 'void do_unblank_screen(void)' - * 'void poke_blanked_console(void)' - * - * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)' - * 'void complement_pos(int currcons, int offset)' - * 'void invert_screen(int currcons, int offset, int count, int shift)' - * - * 'void scrollback(int lines)' - * 'void scrollfront(int lines)' - * - * 'int con_get_font(char *)' - * 'int con_set_font(char *)' - * - * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)' - * 'int mouse_reporting(void)' - * - * 'unsigned long get_video_num_lines(unsigned int console)' - * 'unsigned long get_video_num_columns(unsigned int console)' - * 'unsigned long get_video_size_row(unsigned int console)' - * - * Hopefully this will be a rather complete VT102 implementation. - * - * Beeping thanks to John T Kohl. - * - * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics - * Chars, and VT100 enhancements by Peter MacDonald. - * - * Copy and paste function by Andrew Haylett, - * some enhancements by Alessandro Rubini. - * - * User definable mapping table and font loading by Eugene G. Crosser, - * - * - * Code to check for different video-cards mostly by Galen Hunt, - * - * - * Rudimentary ISO 10646/Unicode/UTF-8 character set support by - * Markus Kuhn, . - * - * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 - * Resizing of consoles, aeb, 940926 - * - * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 - * - * - * 680x0 LINUX support by Arno Griffioen (arno@usn.nl) - * - * 9-Apr-94: Arno Griffioen: fixed scrolling and delete-char bug. - * Scrolling code moved to amicon.c - * - * 18-Apr-94: David Carter [carter@cs.bris.ac.uk]. 680x0 LINUX modified - * Integrated support for new low level driver `amicon_ocs.c' - * - */ - -#define BLANK 0x0020 -#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ - -/* A bitmap for codes <32. A bit of 1 indicates that the code - * corresponding to that bit number invokes some special action - * (such as cursor movement) and should not be displayed as a - * glyph unless the disp_ctrl mode is explicitly enabled. - */ -#define CTRL_ACTION 0x0d00ff81 -#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ - -/* - * Here is the default bell parameters: 750HZ, 1/8th of a second - */ -#define DEFAULT_BELL_PITCH 750 -#define DEFAULT_BELL_DURATION (HZ/8) - -/* - * NOTE!!! We sometimes disable and enable interrupts for a short while - * (to put a word in video IO), but this will work even for keyboard - * interrupts. We know interrupts aren't enabled when getting a keyboard - * interrupt, as we use trap-gates. Hopefully all is well. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -struct tty_driver console_driver; -static int console_refcount; -static struct tty_struct *console_table[MAX_NR_CONSOLES]; -static struct termios *console_termios[MAX_NR_CONSOLES]; -static struct termios *console_termios_locked[MAX_NR_CONSOLES]; - -static void vc_init(unsigned int console, int do_clear); - -static void update_attr(int currcons); -static void gotoxy(int currcons, int new_x, int new_y); -static void save_cur(int currcons); -static void blank_screen(void); -static void unblank_screen(void); -static int con_open(struct tty_struct *, struct file *); -extern void change_console(unsigned int); -static inline void set_cursor(int currcons); -static void reset_terminal(int currcons, int do_clear); -extern void reset_vc(unsigned int new_console); -extern void vt_init(void); -static void set_vesa_blanking(unsigned long arg); -extern void vesa_blank(void); -extern void vesa_unblank(void); -extern void compute_shiftstate(void); -extern void reset_palette(int currcons); -extern void set_palette(void); -void poke_blanked_console(void); -void do_blank_screen(int); - -#if 0 -/* Make sure there are no references left to this variables. */ -unsigned long video_num_lines; -unsigned long video_num_columns; -unsigned long video_size_row; -#endif - -static int printable = 0; /* Is console ready for printing? */ -unsigned long video_font_height; /* Height of current screen font */ -unsigned long video_scan_lines; /* Number of scan lines on screen */ -unsigned long default_font_height; /* Height of default screen font */ -int video_mode_512ch = 0; /* 512-character mode */ -static unsigned short console_charmask = 0x0ff; - -static unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; -struct vc vc_cons [MAX_NR_CONSOLES]; - -/* used by kbd_bh - set by keyboard_interrupt */ - int do_poke_blanked_console = 0; - int console_blanked = 0; -static int blankinterval = 10*60*HZ; -static int vesa_off_interval = 0; -static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ - -/* - * fg_console is the current virtual console, - * last_console is the last used one, - * want_console is the console we want to switch to, - * kmsg_redirect is the console for kernel messages, - */ -int fg_console = 0; -int last_console = 0; -int want_console = -1; -int kmsg_redirect = 0; - -struct consw *conswitchp; - -#define cols (vc_cons[currcons].d->vc_cols) -#define rows (vc_cons[currcons].d->vc_rows) -#define size_row (vc_cons[currcons].d->vc_size_row) -#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) -#define cons_num (vc_cons[currcons].d->vc_num) -#define origin (vc_cons[currcons].d->vc_origin) -#define scr_end (vc_cons[currcons].d->vc_scr_end) -#define pos (vc_cons[currcons].d->vc_pos) -#define top (vc_cons[currcons].d->vc_top) -#define bottom (vc_cons[currcons].d->vc_bottom) -#define x (vc_cons[currcons].d->vc_x) -#define y (vc_cons[currcons].d->vc_y) -#define vc_state (vc_cons[currcons].d->vc_state) -#define npar (vc_cons[currcons].d->vc_npar) -#define par (vc_cons[currcons].d->vc_par) -#define ques (vc_cons[currcons].d->vc_ques) -#define attr (vc_cons[currcons].d->vc_attr) -#define saved_x (vc_cons[currcons].d->vc_saved_x) -#define saved_y (vc_cons[currcons].d->vc_saved_y) -#define translate (vc_cons[currcons].d->vc_translate) -#define G0_charset (vc_cons[currcons].d->vc_G0_charset) -#define G1_charset (vc_cons[currcons].d->vc_G1_charset) -#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) -#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) -#define utf (vc_cons[currcons].d->vc_utf) -#define utf_count (vc_cons[currcons].d->vc_utf_count) -#define utf_char (vc_cons[currcons].d->vc_utf_char) -#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) -#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) -#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) -#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) -#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) -#define decscnm (vc_cons[currcons].d->vc_decscnm) -#define decom (vc_cons[currcons].d->vc_decom) -#define decawm (vc_cons[currcons].d->vc_decawm) -#define deccm (vc_cons[currcons].d->vc_deccm) -#define decim (vc_cons[currcons].d->vc_decim) -#define deccolm (vc_cons[currcons].d->vc_deccolm) -#define need_wrap (vc_cons[currcons].d->vc_need_wrap) -#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled) -#define kmalloced (vc_cons[currcons].d->vc_kmalloced) -#define report_mouse (vc_cons[currcons].d->vc_report_mouse) -#define can_do_color (vc_cons[currcons].d->vc_can_do_color) -#define color (vc_cons[currcons].d->vc_color) -#define s_color (vc_cons[currcons].d->vc_s_color) -#define def_color (vc_cons[currcons].d->vc_def_color) -#define foreground (color & 0x0f) -#define background (color & 0xf0) -#define charset (vc_cons[currcons].d->vc_charset) -#define s_charset (vc_cons[currcons].d->vc_s_charset) -#define intensity (vc_cons[currcons].d->vc_intensity) -#define underline (vc_cons[currcons].d->vc_underline) -#define blink (vc_cons[currcons].d->vc_blink) -#define reverse (vc_cons[currcons].d->vc_reverse) -#define s_intensity (vc_cons[currcons].d->vc_s_intensity) -#define s_underline (vc_cons[currcons].d->vc_s_underline) -#define s_blink (vc_cons[currcons].d->vc_s_blink) -#define s_reverse (vc_cons[currcons].d->vc_s_reverse) -#define ulcolor (vc_cons[currcons].d->vc_ulcolor) -#define halfcolor (vc_cons[currcons].d->vc_halfcolor) -#define tab_stop (vc_cons[currcons].d->vc_tab_stop) -#define palette (vc_cons[currcons].d->vc_palette) -#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) -#define bell_duration (vc_cons[currcons].d->vc_bell_duration) -#define sw (vc_cons[currcons].d->vc_sw) - -#define vcmode (vt_cons[currcons]->vc_mode) -#if 0 /* XXX */ -#define vtmode (vt_cons[currcons]->vt_mode) -#define vtpid (vt_cons[currcons]->vt_pid) -#define vtnewvt (vt_cons[currcons]->vt_newvt) -#endif - -int vc_cons_allocated(unsigned int i) -{ - return (i < MAX_NR_CONSOLES && vc_cons[i].d); -} - -int vc_allocate(unsigned int currcons) /* return 0 on success */ -{ - if (currcons >= MAX_NR_CONSOLES) - return -ENODEV; - if (!vc_cons[currcons].d) { - long p, q; - - /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !suser()) - return -EPERM; - - /* due to the granularity of kmalloc, we waste some memory here */ - /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, screenbuf_size=4000) */ - p = (long) kmalloc(structsize, GFP_KERNEL); - if (!p) - return -ENOMEM; - vc_cons[currcons].d = (struct vc_data *) p; - vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); - - /* ++Geert: sw->con_init determines console size */ - sw = conswitchp; - cons_num = currcons; - sw->con_init (vc_cons[currcons].d); - size_row = cols<<1; - screenbuf_size = rows*size_row; - - q = (long) kmalloc(screenbuf_size, GFP_KERNEL); - if (!q) { - kfree_s((char *) p, structsize); - vc_cons[currcons].d = NULL; - return -ENOMEM; - } - vc_scrbuf[currcons] = (unsigned short *) q; - kmalloced = 1; - vc_init (currcons, 1); - } - return 0; -} - -/* - * Change # of rows and columns (0 means the size of fg_console) - * [this is to be used together with some user program - * like resize that changes the hardware videomode] - */ -int vc_resize(unsigned long lines, unsigned long columns) -{ - unsigned long cc, ll, ss, sr; - unsigned long occ, oll, oss, osr; - unsigned short *p; - unsigned int currcons = fg_console, i; - unsigned short *newscreens[MAX_NR_CONSOLES]; - long ol, nl, rlth, rrem; - - cc = (columns ? columns : cols); - ll = (lines ? lines : rows); - sr = cc << 1; - ss = sr * ll; - - /* - * Some earlier version had all consoles of potentially - * different sizes, but that was really messy. - * So now we only change if there is room for all consoles - * of the same size. - */ - for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { - if (!vc_cons_allocated(currcons)) - newscreens[currcons] = 0; - else { - p = (unsigned short *) kmalloc(ss, GFP_USER); - if (!p) { - for (i = 0; i< currcons; i++) - if (newscreens[i]) - kfree_s(newscreens[i], ss); - return -ENOMEM; - } - newscreens[currcons] = p; - } - } - -#if 0 /* XXX */ - get_scrmem(fg_console); -#endif - - for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { - if (!vc_cons_allocated(currcons)) - continue; - - oll = rows; - occ = cols; - osr = size_row; - oss = screenbuf_size; - - rows = ll; - cols = cc; - size_row = sr; - screenbuf_size = ss; - - rlth = MIN(osr, sr); - rrem = sr - rlth; - ol = origin; - nl = (long) newscreens[currcons]; - if (ll < oll) - ol += (oll - ll) * osr; - - update_attr(currcons); - while (ol < scr_end) { - /* ++Geert: TODO: Because the attributes have different meanings - on monochrome and color, they should really be converted if - can_do_color changes... */ - memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); - if (rrem) - memsetw((void *)(nl + rlth), video_erase_char, rrem); - ol += osr; - nl += sr; - } - - if (kmalloced) - kfree_s(vc_scrbuf[currcons], oss); - vc_scrbuf[currcons] = newscreens[currcons]; - kmalloced = 1; - screenbuf_size = ss; - - origin = (long) video_mem_start = vc_scrbuf[currcons]; - scr_end = video_mem_end = ((long) video_mem_start) + ss; - - if (scr_end > nl) - memsetw((void *) nl, video_erase_char, scr_end - nl); - - /* do part of a reset_terminal() */ - top = 0; - bottom = rows; - gotoxy(currcons, x, y); - save_cur(currcons); - } - -#if 0 /* XXX */ - set_scrmem(fg_console, 0); - set_origin(fg_console); -#endif /* XXX */ - /* don't update in graphics mode */ - if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT) - update_screen(fg_console); - - set_cursor(fg_console); - - return 0; -} - -/* - * ++Geert: Change # of rows and columns for one specific console. - * Of course it's not messy to have all consoles of potentially different sizes, - * except on PCish hardware :-) - * - * This is called by the low level console driver (arch/m68k/console/fbcon.c or - * arch/m68k/console/txtcon.c) - */ -void vc_resize_con(unsigned long lines, unsigned long columns, - unsigned int currcons) -{ - unsigned long cc, ll, ss, sr; - unsigned long occ, oll, oss, osr; - unsigned short *newscreen; - long ol, nl, rlth, rrem; - struct winsize ws; - - if (!columns || !lines || currcons >= MAX_NR_CONSOLES) - return; - - cc = columns; - ll = lines; - sr = cc << 1; - ss = sr * ll; - - if (!vc_cons_allocated(currcons)) - newscreen = 0; - else if (!(newscreen = (unsigned short *) kmalloc(ss, GFP_USER))) - return; - - if (vc_cons_allocated(currcons)) { - oll = rows; - occ = cols; - osr = size_row; - oss = screenbuf_size; - - rows = ll; - cols = cc; - size_row = sr; - screenbuf_size = ss; - - rlth = MIN(osr, sr); - rrem = sr - rlth; - ol = origin; - nl = (long) newscreen; - if (ll < oll) - ol += (oll - ll) * osr; - - update_attr(currcons); - while (ol < scr_end) { - /* ++Geert: TODO: Because the attributes have different meanings - on monochrome and color, they should really be converted if - can_do_color changes... */ - memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); - if (rrem) - memsetw((void *)(nl + rlth), video_erase_char, rrem); - ol += osr; - nl += sr; - } - - if (kmalloced) - kfree_s(vc_scrbuf[currcons], oss); - vc_scrbuf[currcons] = newscreen; - kmalloced = 1; - screenbuf_size = ss; - - origin = (long) video_mem_start = vc_scrbuf[currcons]; - scr_end = video_mem_end = ((long)video_mem_start) + ss; - - if (scr_end > nl) - memsetw((void *) nl, video_erase_char, scr_end - nl); - - /* do part of a reset_terminal() */ - top = 0; - bottom = rows; - gotoxy(currcons, x, y); - save_cur(currcons); - - ws.ws_row = rows; - ws.ws_col = cols; - if (memcmp(&ws, &console_table[currcons]->winsize, sizeof (struct winsize)) && - console_table[currcons]->pgrp > 0) - kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); - console_table[currcons]->winsize = ws; - } - - /* don't update in graphics mode */ - if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT) - update_screen(fg_console); -} - -void vc_disallocate(unsigned int currcons) -{ - if (vc_cons_allocated(currcons)) { - if (kmalloced) - kfree_s(vc_scrbuf[currcons], screenbuf_size); - if (currcons >= MIN_NR_CONSOLES) - kfree_s(vc_cons[currcons].d, structsize); - vc_cons[currcons].d = 0; - } -} - - -#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) -#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) -#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) - -#define decarm VC_REPEAT -#define decckm VC_CKMODE -#define kbdapplic VC_APPLIC -#define lnm VC_CRLF - -/* - * this is what the terminal answers to a ESC-Z or csi0c query. - */ -#define VT100ID "\033[?1;2c" -#define VT102ID "\033[?6c" - -static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 }; - -/* the default colour table, for VGA+ colour systems */ -int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; -int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; -int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; - -/* - * gotoxy() must verify all boundaries, because the arguments - * might also be negative. If the given position is out of - * bounds, the cursor is placed at the nearest margin. - */ -static void gotoxy(int currcons, int new_x, int new_y) -{ - int min_y, max_y; - - if (new_x < 0) - x = 0; - else - if (new_x >= cols) - x = cols - 1; - else - x = new_x; - if (decom) { - min_y = top; - max_y = bottom; - } else { - min_y = 0; - max_y = rows; - } - if (new_y < min_y) - y = min_y; - else if (new_y >= max_y) - y = max_y - 1; - else - y = new_y; - pos = video_mem_start + y * cols + x; - need_wrap = 0; -} - -/* for absolute user moves, when decom is set */ -static void gotoxay(int currcons, int new_x, int new_y) -{ - gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); -} - -static void hide_cursor(int currcons) -{ - sw->con_cursor(vc_cons[currcons].d,CM_ERASE); - return; -} - -static void set_cursor(int currcons) -{ - if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) - return; - if (deccm) - sw->con_cursor(vc_cons[currcons].d,CM_DRAW); - else - hide_cursor(currcons); - return; -} - -void no_scroll(char *str, int *ints) -{ - /* - * no_scroll currently does nothing on the m68k. - */ -} - -/* - * Arno: - * Why do we need these? The keyboard code doesn't seem to do anything - * with them either... - */ -void scrollfront(int l) -{ - return; -} - -void scrollback(int l) -{ - return; -} - -static void scrup(int currcons, unsigned int t, unsigned int b, int nr) -{ - unsigned short *p; - int i; - - if (b > rows || t >= b) - return; - - memmove (video_mem_start + t * cols, - video_mem_start + (t + nr) * cols, - (b - t - nr) * cols * 2); - - p = video_mem_start + (b - nr) * cols; - for (i = nr * cols; i > 0; i--) - *p++ = video_erase_char; - - if (currcons != fg_console) - return; -/* - * Arno: - * Scrolling has now been moved to amicon.c where it should have - * been all along. - */ - sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr); - - return; - -} - -static void scrdown(int currcons, unsigned int t, unsigned int b, - int nr) -{ - unsigned short *p; - int i; - - if (b > rows || t >= b) - return; - - memmove (video_mem_start + (t + nr) * cols, - video_mem_start + t * cols, - (b - t - nr) * cols * 2); - - p = video_mem_start + t * cols; - for (i = nr * cols; i > 0; i--) - *p++ = video_erase_char; - - if (currcons != fg_console) - return; -/* - * Arno: - * Scrolling has now been moved to amicon.c where it should have - * been all along. - */ - sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr); - - return; -} - -static void lf(int currcons) -{ - /* don't scroll if above bottom of scrolling region, or - * if below scrolling region - */ - if (y+1 == bottom) - scrup(currcons,top,bottom, 1); - else if (y < rows-1) { - y++; - pos += cols; - } - need_wrap = 0; -} - -static void ri(int currcons) -{ - /* don't scroll if below top of scrolling region, or - * if above scrolling region - */ - if (y == top) - scrdown(currcons,top,bottom, 1); - else if (y > 0) { - y--; - pos -= cols; - } - need_wrap = 0; -} - -static inline void cr(int currcons) -{ - pos -= x; - need_wrap = x = 0; -} - -static inline void bs(int currcons) -{ - if (x) { - pos--; - x--; - need_wrap = 0; - } -} - -static inline void del(int currcons) -{ - /* ignored */ -} - -static void csi_J(int currcons, int vpar) -{ - unsigned long count; - unsigned short *start; - - switch (vpar) { - case 0: /* erase from cursor to end of display */ - count = (video_mem_start - + cols * rows - - pos); - start = pos; - if (currcons != fg_console) - break; - /* 680x0 do in two stages */ - sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); - sw->con_clear(vc_cons[currcons].d,y+1,0,rows-y-1, cols); - break; - case 1: /* erase from start to cursor */ - count = pos - video_mem_start + 1; - start = video_mem_start; - if (currcons != fg_console) - break; - /* 680x0 do in two stages */ - sw->con_clear(vc_cons[currcons].d,0,0,y, cols); - sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); - break; - case 2: /* erase whole display */ - count = cols * rows; - start = video_mem_start; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,0,0,rows, cols); - break; - default: - return; - } - while (count-- > 0) - *start++ = video_erase_char; - need_wrap = 0; -} - -static void csi_K(int currcons, int vpar) -{ - unsigned long count; - unsigned short *start; - - switch (vpar) { - case 0: /* erase from cursor to end of line */ - count = cols - x; - start = pos; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); - break; - case 1: /* erase from start of line to cursor */ - start = pos - x; - count = x + 1; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); - break; - case 2: /* erase whole line */ - start = pos - x; - count = cols; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,y,0,1,cols); - break; - default: - return; - } - while (count-- > 0) - *start++ = video_erase_char; - need_wrap = 0; -} - -static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ -{ /* not vt100? */ - unsigned long count; - unsigned short * start; - - if (!vpar) - vpar++; - - start = pos; - count = (vpar > cols-x) ? (cols-x) : vpar; - - if (currcons == fg_console) - sw->con_clear(vc_cons[currcons].d,y,x,1,count); - - while (count-- > 0) - *start++ = video_erase_char; - need_wrap = 0; -} - -/* - * Arno: - * On 680x0 attributes are currently not used. This piece of code - * seems hardware independent, but uses the EGA/VGA way of representing - * attributes. - * TODO: modify for 680x0 and add attribute processing to putc code. - * - * ++roman: I completely changed the attribute format for monochrome - * mode (!can_do_color). The formerly used MDA (monochrome display - * adapter) format didn't allow the combination of certain effects. - * Now the attribute is just a bit vector: - * Bit 0..1: intensity (0..2) - * Bit 2 : underline - * Bit 3 : reverse - * Bit 7 : blink - */ -static void update_attr(int currcons) -{ - if (!can_do_color) { - /* Special treatment for monochrome */ - attr = intensity | - (underline ? 4 : 0) | - ((reverse ^ decscnm) ? 8 : 0) | - (blink ? 0x80 : 0); - video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0); - return; - } - - attr = color; - if (underline) - attr = (attr & 0xf0) | ulcolor; - else if (intensity == 0) - attr = (attr & 0xf0) | halfcolor; - if (reverse ^ decscnm) - attr = reverse_video_char(attr); - if (blink) - attr ^= 0x80; - if (intensity == 2) - attr ^= 0x08; - if (decscnm) - video_erase_char = (reverse_video_char(color) << 8) | ' '; - else - video_erase_char = (color << 8) | ' '; -} - -static void default_attr(int currcons) -{ - intensity = 1; - underline = 0; - reverse = 0; - blink = 0; - color = def_color; -} - -static void csi_m(int currcons) -{ - int i; - - for (i=0;i<=npar;i++) - switch (par[i]) { - case 0: /* all attributes off */ - default_attr(currcons); - break; - case 1: - intensity = 2; - break; - case 2: - intensity = 0; - break; - case 4: - underline = 1; - break; - case 5: - blink = 1; - break; - case 7: - reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - translate = set_translate(charset == 0 - ? G0_charset - : G1_charset); - disp_ctrl = 0; - toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, let's - * chars < 32 be displayed as ROM chars. - */ - translate = set_translate(IBMPC_MAP); - disp_ctrl = 1; - toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - translate = set_translate(IBMPC_MAP); - disp_ctrl = 1; - toggle_meta = 1; - break; - case 21: - case 22: - intensity = 1; - break; - case 24: - underline = 0; - break; - case 25: - blink = 0; - break; - case 27: - reverse = 0; - break; - case 38: /* ANSI X3.64-1979 (SCO-ish?) - * Enables underscore, white foreground - * with white underscore (Linux - use - * default foreground). - */ - color = (def_color & 0x0f) | background; - underline = 1; - break; - case 39: /* ANSI X3.64-1979 (SCO-ish?) - * Disable underline option. - * Reset colour to default? It did this - * before... - */ - color = (def_color & 0x0f) | background; - underline = 0; - break; - case 49: - color = (def_color & 0xf0) | foreground; - break; - default: - if (par[i] >= 30 && par[i] <= 37) - color = color_table[par[i]-30] - | background; - else if (par[i] >= 40 && par[i] <= 47) - color = (color_table[par[i]-40]<<4) - | foreground; - break; - } - update_attr(currcons); -} - -static void respond_string(const char * p, struct tty_struct * tty) -{ - while (*p) { - tty_insert_flip_char(tty, *p, 0); - p++; - } - tty_schedule_flip(tty); -} - -static inline void cursor_report(int currcons, struct tty_struct * tty) -{ - char buf[40]; - - sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1); - respond_string(buf, tty); -} - -static inline void status_report(struct tty_struct * tty) -{ - respond_string("\033[0n", tty); /* Terminal ok */ -} - -static inline void respond_ID(struct tty_struct * tty) -{ - respond_string(VT102ID, tty); -} - -void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) -{ - char buf[8]; - - sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), - (char)('!' + mry)); - respond_string(buf, tty); -} - -/* invoked via ioctl(TIOCLINUX) and through set_selection */ -int mouse_reporting(void) -{ - int currcons = fg_console; - - return report_mouse; -} - -int tioclinux(struct tty_struct *tty, unsigned long arg) -{ - char type, data; - - if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) - return -EINVAL; - if (current->tty != tty && !suser()) - return -EPERM; - if (get_user(type, (char *)arg)) - return -EFAULT; - switch (type) - { - case 2: - return set_selection(arg, tty, 1); - case 3: - return paste_selection(tty); - case 4: - do_unblank_screen(); - return 0; - case 5: - return sel_loadlut(arg); - case 6: - - /* - * Make it possible to react to Shift+Mousebutton. - * Note that 'shift_state' is an undocumented - * kernel-internal variable; programs not closely - * related to the kernel should not use this. - */ - data = shift_state; - return put_user(data, (char *) arg); - case 7: - data = mouse_reporting(); - return put_user(data, (char *) arg); - case 10: - set_vesa_blanking(arg); - return 0; - case 11: /* set kmsg redirect */ - if (!suser()) - return -EPERM; - if (get_user(data, (char *)arg+1)) - return -EFAULT; - kmsg_redirect = data; - return 0; - case 12: /* get fg_console */ - return fg_console; - } - return -EINVAL; -} - -static inline unsigned short *screenpos(int currcons, int offset, int viewed) -{ - unsigned short *p = (unsigned short *)(origin + offset); -#if 0 - if (viewed && currcons == fg_console) - p -= (__real_origin - __origin); -#endif - return p; -} - -/* Note: inverting the screen twice should revert to the original state */ -void invert_screen(int currcons, int offset, int count, int viewed) -{ - unsigned short *p; - unsigned short xx, yy, oldattr; - - count /= 2; - p = screenpos(currcons, offset, viewed); - xx = (offset >> 1) % cols; - yy = (offset >> 1) / cols; - oldattr = attr; - if (can_do_color) - while (count--) { - unsigned short old = scr_readw(p); - unsigned short new = reverse_video_short(old); - scr_writew(new, p); - p++; - if (currcons != fg_console) - continue; - attr = new >> 8; - sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); - if (++xx == cols) - xx = 0, ++yy; - } - else - while (count--) { - unsigned short old = scr_readw(p); - unsigned short new = old ^ 0x800; - scr_writew(new, p); - p++; - if (currcons != fg_console) - continue; - attr = new >> 8; - sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); - if (++xx == cols) - xx = 0, ++yy; - } - attr = oldattr; -} - -/* used by selection: complement pointer position */ -void complement_pos(int currcons, int offset) -{ - static unsigned short *p = NULL; - static unsigned short old = 0; - static unsigned short oldx = 0, oldy = 0; - unsigned short new, oldattr; - - oldattr = attr; - if (p) { - scr_writew(old, p); - if (currcons == fg_console) { - attr = old >> 8; - sw->con_putc(vc_cons[currcons].d, old & 0xff, oldy, oldx); - attr = oldattr; - } - } - if (offset == -1) - p = NULL; - else { - p = screenpos(currcons, offset, 1); - old = scr_readw(p); - oldx = (offset >> 1) % cols; - oldy = (offset >> 1) / cols; - if (can_do_color) - new = old ^ 0x7700; - else - new = old ^ 0x800; - scr_writew(new, p); - if (currcons == fg_console) { - attr = new >> 8; - sw->con_putc(vc_cons[currcons].d, new & 0xff, oldy, oldx); - attr = oldattr; - } - } -} - -/* used by selection */ -unsigned short screen_word(int currcons, int offset, int viewed) -{ - return scr_readw(screenpos(currcons, offset, viewed)); -} - -/* used by selection - convert a screen word to a glyph number */ -int scrw2glyph(unsigned short scr_word) -{ - return ( video_mode_512ch ) - ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff) - : scr_word & 0x00ff; -} - -/* used by vcs - note the word offset */ -unsigned short *screen_pos(int currcons, int w_offset, int viewed) -{ - return screenpos(currcons, 2 * w_offset, viewed); -} - -void getconsxy(int currcons, char *p) -{ - p[0] = x; - p[1] = y; -} - -void putconsxy(int currcons, char *p) -{ - gotoxy(currcons, p[0], p[1]); - set_cursor(currcons); -} - -static void set_mode(int currcons, int on_off) -{ - int i; - - for (i=0; i<=npar; i++) - if (ques) switch(par[i]) { /* DEC private modes set/reset */ - case 1: /* Cursor keys send ^[Ox/^[[x */ - if (on_off) - set_kbd(decckm); - else - clr_kbd(decckm); - break; - case 3: /* 80/132 mode switch unimplemented */ - deccolm = on_off; -#if 0 - (void) vc_resize(rows, deccolm ? 132 : 80); - /* this alone does not suffice; some user mode - utility has to change the hardware regs */ -#endif - break; - case 5: /* Inverted screen on/off */ - if (decscnm != on_off) { - decscnm = on_off; - invert_screen(currcons, 0, screenbuf_size, 0); - update_attr(currcons); - } - break; - case 6: /* Origin relative/absolute */ - decom = on_off; - gotoxay(currcons,0,0); - break; - case 7: /* Autowrap on/off */ - decawm = on_off; - break; - case 8: /* Autorepeat on/off */ - if (on_off) - set_kbd(decarm); - else - clr_kbd(decarm); - break; - case 9: - report_mouse = on_off ? 1 : 0; - break; - case 25: /* Cursor on/off */ - deccm = on_off; - set_cursor(currcons); - break; - case 1000: - report_mouse = on_off ? 2 : 0; - break; - } else switch(par[i]) { /* ANSI modes set/reset */ - case 3: /* Monitor (display ctrls) */ - disp_ctrl = on_off; - break; - case 4: /* Insert Mode on/off */ - decim = on_off; - break; - case 20: /* Lf, Enter == CrLf/Lf */ - if (on_off) - set_kbd(lnm); - else - clr_kbd(lnm); - break; - } -} - -static void setterm_command(int currcons) -{ - switch(par[0]) { - case 1: /* set color for underline mode */ - if (can_do_color && par[1] < 16) { - ulcolor = color_table[par[1]]; - if (underline) - update_attr(currcons); - } - break; - case 2: /* set color for half intensity mode */ - if (can_do_color && par[1] < 16) { - halfcolor = color_table[par[1]]; - if (intensity == 0) - update_attr(currcons); - } - break; - case 8: /* store colors as defaults */ - def_color = attr; - default_attr(currcons); - update_attr(currcons); - break; - case 9: /* set blanking interval */ - blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - poke_blanked_console(); - break; - case 10: /* set bell frequency in Hz */ - if (npar >= 1) - bell_pitch = par[1]; - else - bell_pitch = DEFAULT_BELL_PITCH; - break; - case 11: /* set bell duration in msec */ - if (npar >= 1) - bell_duration = (par[1] < 2000) ? - par[1]*HZ/1000 : 0; - else - bell_duration = DEFAULT_BELL_DURATION; - break; - case 12: /* bring specified console to the front */ - if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) - update_screen(par[1]-1); - break; - case 13: /* unblank the screen */ - unblank_screen(); - break; - case 14: /* set vesa powerdown interval */ - vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - break; - } -} - -static inline void insert_char(int currcons) -{ - int i; - unsigned short *p = pos; - - for (i = cols - x - 2; i >= 0; i--) - p[i + 1] = p[i]; - *pos = video_erase_char; - need_wrap = 0; - - if (currcons != fg_console) - return; - - /* Arno: - * Move the remainder of the line (-1 character) one spot to the right - */ - sw->con_bmove(vc_cons[currcons].d,y,x,y,x+1,1,(cols-x-1)); - /* - * Print the erase char on the current position - */ - sw->con_putc(vc_cons[currcons].d,(video_erase_char & 0x00ff),y,x); -} - -static void csi_at(int currcons, unsigned int nr) -{ - int i; - unsigned short *p; - - if (nr > cols - x) - nr = cols - x; - else if (!nr) - nr = 1; - - p = pos + cols - x - nr; - while (--p >= pos) - p[nr] = *p; - for (i = 0; i < nr; i++) - *++p = video_erase_char; - need_wrap = 0; - - if (currcons != fg_console) - return; - - sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr, - 1, cols - x - nr); - while (nr--) - sw->con_putc (vc_cons[currcons].d, - video_erase_char & 0x00ff, y, x + nr); -} - -static void csi_L(int currcons, unsigned int nr) -{ - if (nr > rows) - nr = rows; - else if (!nr) - nr = 1; - scrdown (currcons, y, bottom, nr); - need_wrap = 0; -} - -static void csi_P(int currcons, unsigned int nr) -{ - int i; - unsigned short *p, *end; - - if (nr > cols - x) - nr = cols - x; - else if (!nr) - nr = 1; - - p = pos; - end = pos + cols - x - nr; - while (p < end) - *p = p[nr], p++; - for (i = 0; i < nr; i++) - *p++ = video_erase_char; - need_wrap = 0; - - if (currcons != fg_console) - return; - - sw->con_bmove (vc_cons[currcons].d, y, x + nr, y, x, - 1, cols - x - nr); - - while (nr--) - sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, - y, cols - 1 - nr); -} - -static void csi_M(int currcons, unsigned int nr) -{ - if (nr > rows) - nr = rows; - else if (!nr) - nr=1; - scrup (currcons, y, bottom, nr); - need_wrap = 0; -} - -static void save_cur(int currcons) -{ - saved_x = x; - saved_y = y; - s_intensity = intensity; - s_underline = underline; - s_blink = blink; - s_reverse = reverse; - s_charset = charset; - s_color = color; - saved_G0 = G0_charset; - saved_G1 = G1_charset; -} - -static void restore_cur(int currcons) -{ - gotoxy(currcons,saved_x,saved_y); - intensity = s_intensity; - underline = s_underline; - blink = s_blink; - reverse = s_reverse; - charset = s_charset; - color = s_color; - G0_charset = saved_G0; - G1_charset = saved_G1; - translate = set_translate(charset ? G1_charset : G0_charset); - update_attr(currcons); - need_wrap = 0; -} - -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; - -static void reset_terminal(int currcons, int do_clear) -{ - top = 0; - bottom = rows; - vc_state = ESnormal; - ques = 0; - translate = set_translate(LAT1_MAP); - G0_charset = LAT1_MAP; - G1_charset = GRAF_MAP; - charset = 0; - need_wrap = 0; - report_mouse = 0; - utf = 0; - utf_count = 0; - - disp_ctrl = 0; - toggle_meta = 0; - - decscnm = 0; - decom = 0; - decawm = 1; - deccm = 1; - decim = 0; - - set_kbd(decarm); - clr_kbd(decckm); - clr_kbd(kbdapplic); - clr_kbd(lnm); - kbd_table[currcons].lockstate = 0; - kbd_table[currcons].slockstate = 0; - kbd_table[currcons].ledmode = LED_SHOW_FLAGS; - kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; - set_leds(); - - default_attr(currcons); - update_attr(currcons); - - tab_stop[0] = 0x01010100; - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0x01010101; - - bell_pitch = DEFAULT_BELL_PITCH; - bell_duration = DEFAULT_BELL_DURATION; - - gotoxy(currcons,0,0); - save_cur(currcons); - if (do_clear) - csi_J(currcons,2); -} - -/* - * Turn the Scroll-Lock LED on when the tty is stopped - */ -static void con_stop(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = MINOR(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -/* - * Turn the Scroll-Lock LED off when the console is started - */ -static void con_start(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = MINOR(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -static void con_flush_chars(struct tty_struct *tty) -{ - unsigned int currcons; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - - currcons = vt->vc_num; - if (vcmode != KD_GRAPHICS) - set_cursor(currcons); -} - -static int do_con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int c, tc, ok, n = 0; - unsigned int currcons; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - - currcons = vt->vc_num; - if (!vc_cons_allocated(currcons)) { - /* could this happen? */ - static int error = 0; - if (!error) { - error = 1; - printk("con_write: tty %d not allocated\n", currcons+1); - } - return 0; - } - - /* undraw cursor first */ - if (currcons == fg_console) - hide_cursor(currcons); - - /* clear the selection */ - if (currcons == sel_cons) - clear_selection(); - - disable_bh(CONSOLE_BH); - while (count) { - enable_bh(CONSOLE_BH); - if (from_user) - get_user(c, buf); - else - c = *buf; - buf++; n++; count--; - disable_bh(CONSOLE_BH); - - if (utf) { - /* Combine UTF-8 into Unicode */ - /* Incomplete characters silently ignored */ - if(c > 0x7f) { - if (utf_count > 0 && (c & 0xc0) == 0x80) { - utf_char = (utf_char << 6) | (c & 0x3f); - utf_count--; - if (utf_count == 0) - tc = c = utf_char; - else continue; - } else { - if ((c & 0xe0) == 0xc0) { - utf_count = 1; - utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - utf_count = 2; - utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - utf_count = 3; - utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - utf_count = 4; - utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - utf_count = 5; - utf_char = (c & 0x01); - } else - utf_count = 0; - continue; - } - } else { - tc = c; - utf_count = 0; - } - } else { /* no utf */ - tc = translate[toggle_meta ? (c|0x80) : c]; - } - - /* If the original code was a control character we - * only allow a glyph to be displayed if the code is - * not normally used (such as for cursor movement) or - * if the disp_ctrl mode has been explicitly enabled. - * Certain characters (as given by the CTRL_ALWAYS - * bitmap) are always displayed as control characters, - * as the console would be pretty useless without - * them; to display an arbitrary font position use the - * direct-to-font zone in UTF-8 mode. - */ - ok = tc && (c >= 32 || - (!utf && !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1))) - && (c != 127 || disp_ctrl) - && (c != 128+27); - - if (vc_state == ESnormal && ok) { - /* Now try to find out how to display it */ - tc = conv_uni_to_pc(tc); - if ( tc == -4 ) { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ - tc = conv_uni_to_pc(0xfffd); - } else if ( tc == -3 ) { - /* Bad hash table -- hope for the best */ - tc = c; - } - if (tc & ~console_charmask) - continue; /* Conversion failed */ - - if (need_wrap) { - cr(currcons); - lf(currcons); - } - -#if 1 /* XXX */ - /* DPC: 1994-04-12 - * Speed up overstrike mode, using new putcs. - * - * P.S. I hate 8 spaces per tab! Use Emacs! - */ - - /* Only use this for the foreground console, - where we really draw the chars */ - - if (count > 2 && - !decim && !utf && currcons == fg_console) { - static char putcs_buf[256]; - char *p = putcs_buf; - int putcs_count = 1; - ushort nextx = x + 1; - - *p++ = tc; - *pos++ = tc | (attr << 8); - - if (nextx == cols) { - sw->con_putc(vc_cons[currcons].d, - *putcs_buf, y, x); - pos--; - need_wrap = decawm; - continue; - } - - while (count) - { - enable_bh(CONSOLE_BH); - if (from_user) - get_user(c, buf); - else - c = *buf; - disable_bh(CONSOLE_BH); - tc = translate[toggle_meta ? (c|0x80) : c]; - if (!tc || - !(c >= 32 - || !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1))) - break; - tc = conv_uni_to_pc(tc); - if (tc == -4) - tc = conv_uni_to_pc(0xfffd); - else if (tc == -3) - tc = c; - - buf++; n++; count--; - if (tc & ~console_charmask) - continue; /* Conversion failed */ - - *p++ = tc; - *pos++ = tc | (attr << 8); - ++putcs_count; - ++nextx; - if (nextx == cols || - putcs_count == sizeof (putcs_buf)) - break; - } - - sw->con_putcs(vc_cons[currcons].d, - putcs_buf, putcs_count, y, x); - if (nextx == cols) { - pos--; - x = cols-1; - need_wrap = decawm; - } else - x += putcs_count; - continue; - } - - /* DPC: End of putcs support */ -#endif - - if (decim) - insert_char(currcons); - *pos = (attr << 8) + tc; - if (currcons == fg_console) - sw->con_putc(vc_cons[currcons].d,tc,y,x); - if (x == cols - 1) - need_wrap = decawm; - else { - pos++; - x++; - } - continue; - } - - /* - * Control characters can be used in the _middle_ - * of an escape sequence. - */ - switch (c) { - case 0: - continue; - case 7: - if (bell_duration) - kd_mksound(bell_pitch, bell_duration); - continue; - case 8: - bs(currcons); - continue; - case 9: - pos -= x; - while (x < cols - 1) { - x++; - if (tab_stop[x >> 5] & (1 << (x & 31))) - break; - } - pos += x; - continue; - case 10: case 11: case 12: - lf(currcons); - if (!is_kbd(lnm)) - continue; - case 13: - cr(currcons); - continue; - case 14: - charset = 1; - translate = set_translate(G1_charset); - disp_ctrl = 1; - continue; - case 15: - charset = 0; - translate = set_translate(G0_charset); - disp_ctrl = 0; - continue; - case 24: case 26: - vc_state = ESnormal; - continue; - case 27: - vc_state = ESesc; - continue; - case 127: - del(currcons); - continue; - case 128+27: - vc_state = ESsquare; - continue; - } - switch(vc_state) { - case ESesc: - vc_state = ESnormal; - switch (c) { - case '[': - vc_state = ESsquare; - continue; - case ']': - vc_state = ESnonstd; - continue; - case '%': - vc_state = ESpercent; - continue; - case 'E': - cr(currcons); - lf(currcons); - continue; - case 'M': - ri(currcons); - continue; - case 'D': - lf(currcons); - continue; - case 'H': - tab_stop[x >> 5] |= (1 << (x & 31)); - continue; - case 'Z': - respond_ID(tty); - continue; - case '7': - save_cur(currcons); - continue; - case '8': - restore_cur(currcons); - continue; - case '(': - vc_state = ESsetG0; - continue; - case ')': - vc_state = ESsetG1; - continue; - case '#': - vc_state = EShash; - continue; - case 'c': - reset_terminal(currcons,1); - continue; - case '>': /* Numeric keypad */ - clr_kbd(kbdapplic); - continue; - case '=': /* Appl. keypad */ - set_kbd(kbdapplic); - continue; - } - continue; - case ESnonstd: - if (c=='P') { /* palette escape sequence */ - for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { - par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; - if (npar==7) { - int i = par[0]*3, j = 1; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i] += par[j]; - set_palette() ; - vc_state = ESnormal; - } - } else - vc_state = ESnormal; - continue; - case ESsquare: - for(npar = 0 ; npar < NPAR ; npar++) - par[npar] = 0; - npar = 0; - vc_state = ESgetpars; - if (c == '[') { /* Function key */ - vc_state=ESfunckey; - continue; - } - ques = (c=='?'); - if (ques) - continue; - case ESgetpars: - if (c==';' && npar='0' && c<='9') { - par[npar] *= 10; - par[npar] += c-'0'; - continue; - } else vc_state=ESgotpars; - case ESgotpars: - vc_state = ESnormal; - switch(c) { - case 'h': - set_mode(currcons,1); - continue; - case 'l': - set_mode(currcons,0); - continue; - case 'n': - if (!ques) - if (par[0] == 5) - status_report(tty); - else if (par[0] == 6) - cursor_report(currcons,tty); - continue; - } - if (ques) { - ques = 0; - continue; - } - switch(c) { - case 'G': case '`': - if (par[0]) par[0]--; - gotoxy(currcons,par[0],y); - continue; - case 'A': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y-par[0]); - continue; - case 'B': case 'e': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y+par[0]); - continue; - case 'C': case 'a': - if (!par[0]) par[0]++; - gotoxy(currcons,x+par[0],y); - continue; - case 'D': - if (!par[0]) par[0]++; - gotoxy(currcons,x-par[0],y); - continue; - case 'E': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y+par[0]); - continue; - case 'F': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y-par[0]); - continue; - case 'd': - if (par[0]) par[0]--; - gotoxay(currcons,x,par[0]); - continue; - case 'H': case 'f': - if (par[0]) par[0]--; - if (par[1]) par[1]--; - gotoxay(currcons,par[1],par[0]); - continue; - case 'J': - csi_J(currcons,par[0]); - continue; - case 'K': - csi_K(currcons,par[0]); - continue; - case 'L': - csi_L(currcons,par[0]); - continue; - case 'M': - csi_M(currcons,par[0]); - continue; - case 'P': - csi_P(currcons,par[0]); - continue; - case 'c': - if (!par[0]) - respond_ID(tty); - continue; - case 'g': - if (!par[0]) - tab_stop[x >> 5] &= ~(1 << (x & 31)); - else if (par[0] == 3) { - tab_stop[0] = - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0; - } - continue; - case 'm': - csi_m(currcons); - continue; - case 'q': /* DECLL - but only 3 leds */ - /* map 0,1,2,3 to 0,1,2,4 */ - if (par[0] < 4) - setledstate(kbd_table + currcons, - (par[0] < 3) ? par[0] : 4); - continue; - case 'r': - if (!par[0]) - par[0]++; - if (!par[1]) - par[1] = rows; - /* Minimum allowed region is 2 lines */ - if (par[0] < par[1] && - par[1] <= rows) { - top=par[0]-1; - bottom=par[1]; - gotoxay(currcons,0,0); - } - continue; - case 's': - save_cur(currcons); - continue; - case 'u': - restore_cur(currcons); - continue; - case 'X': - csi_X(currcons, par[0]); - continue; - case '@': - csi_at(currcons,par[0]); - continue; - case ']': /* setterm functions */ - setterm_command(currcons); - continue; - } - continue; - case ESpercent: - vc_state = ESnormal; - switch (c) { - case '@': /* defined in ISO 2022 */ - utf = 0; - continue; - case 'G': /* prelim official escape code */ - case '8': /* retained for compatibility */ - utf = 1; - continue; - } - continue; - case ESfunckey: - vc_state = ESnormal; - continue; - case EShash: - vc_state = ESnormal; - if (c == '8') { - /* DEC screen alignment test. kludge :-) */ - video_erase_char = - (video_erase_char & 0xff00) | 'E'; - /* Arno: - * Doesn't work, because csi_J(c,2) - * calls con_clear and doesn't print - * the erase char.. - */ - csi_J(currcons, 2); - video_erase_char = - (video_erase_char & 0xff00) | ' '; - } - continue; - case ESsetG0: - if (c == '0') - G0_charset = GRAF_MAP; - else if (c == 'B') - G0_charset = LAT1_MAP; - else if (c == 'U') - G0_charset = IBMPC_MAP; - else if (c == 'K') - G0_charset = USER_MAP; - if (charset == 0) - translate = set_translate(G0_charset); - vc_state = ESnormal; - continue; - case ESsetG1: - if (c == '0') - G1_charset = GRAF_MAP; - else if (c == 'B') - G1_charset = LAT1_MAP; - else if (c == 'U') - G1_charset = IBMPC_MAP; - else if (c == 'K') - G1_charset = USER_MAP; - if (charset == 1) - translate = set_translate(G1_charset); - vc_state = ESnormal; - continue; - default: - vc_state = ESnormal; - } - } - enable_bh(CONSOLE_BH); - return n; -} - -static int con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int retval; - - retval = do_con_write(tty, from_user, buf, count); - con_flush_chars(tty); - - return retval; -} - -static void con_put_char(struct tty_struct *tty, unsigned char ch) -{ - do_con_write(tty, 0, &ch, 1); -} - -static int con_write_room(struct tty_struct *tty) -{ - if (tty->stopped) - return 0; - return 4096; /* No limit, really; we're not buffering */ -} - -static int con_chars_in_buffer(struct tty_struct *tty) -{ - return 0; /* we're not buffering */ -} - -void poke_blanked_console(void) -{ - timer_active &= ~(1<vc_mode == KD_GRAPHICS) - return; - if (console_blanked) { - timer_table[BLANK_TIMER].fn = unblank_screen; - timer_table[BLANK_TIMER].expires = 0; - timer_active |= 1< 0) { - c = *(b++); - if (c == 10 || c == 13 || c == 8 || need_wrap) { - if ((cnt = b - start - 1) > 0) { - sw->con_putcs(vc_cons[currcons].d, - start, cnt, y, x); - x += cnt; - if (need_wrap) - x--; - } - - if (c == 8) { /* backspace */ - bs(currcons); - start = b; - myx = x; - continue; - } - if (c != 13) - lf(currcons); - cr(currcons); - - if (c == 10 || c == 13) { - start = b; myx = x; continue; - } - - start = b-1; myx = x; - } - - *pos = c | (attr << 8); - if (myx == cols - 1) { - need_wrap = 1; - continue; - } - pos++; - myx++; - } - - if ((cnt = b - start) > 0) { - sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); - x += cnt; - if (x == cols){ - x--; - need_wrap = 1; - } - } - - set_cursor(currcons); - poke_blanked_console(); - printing = 0; -} - -static int vt_console_device(void) -{ - return MKDEV(TTY_MAJOR, fg_console + 1); -} - -extern void keyboard_wait_for_keypress(void); - -struct console vt_console_driver = { - vt_console_print, do_unblank_screen, - keyboard_wait_for_keypress, vt_console_device -}; -#endif - -/* - * con_throttle and con_unthrottle are only used for - * paste_selection(), which has to stuff in a large number of - * characters... - */ -static void con_throttle(struct tty_struct *tty) -{ -} - -static void con_unthrottle(struct tty_struct *tty) -{ - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - - wake_up_interruptible(&vt->paste_wait); -} - -static void vc_init(unsigned int currcons, int do_clear) -{ - long base = (long) vc_scrbuf[currcons]; - - pos = (unsigned short *)(origin = (ulong)video_mem_start = base); - scr_end = base + screenbuf_size; - video_mem_end = base + screenbuf_size; - reset_vc(currcons); - def_color = 0x07; /* white */ - ulcolor = 0x0f; /* bold white */ - halfcolor = 0x08; /* grey */ - vt_cons[currcons]->paste_wait = 0; - reset_terminal(currcons, do_clear); -} - -/* - * This is the console switching bottom half handler. - * - * Doing console switching in a bottom half handler allows - * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt), while still giving - * us the option to easily disable it to avoid races when we - * need to write to the console. - */ -static void console_bh(void) -{ - if (want_console >= 0) { - if (want_console != fg_console) { - change_console(want_console); - /* we only changed when the console had already - been allocated - a new console is not created - in an interrupt routine */ - } - want_console = -1; - } - if (do_poke_blanked_console) { /* do not unblank for a LED change */ - do_poke_blanked_console = 0; - poke_blanked_console(); - } -} - -/* - * unsigned long con_init(unsigned long); - * - * This routine initializes console interrupts, and does nothing - * else. If you want the screen to clear, call tty_write with - * the appropriate escape-sequence. - * - * Reads the information preserved by setup.s to determine the current display - * type and sets everything accordingly. - */ -__initfunc(unsigned long con_init(unsigned long kmem_start)) -{ - const char *display_desc = "????"; - unsigned int currcons = 0; - extern int serial_debug; - - memset(&console_driver, 0, sizeof(struct tty_driver)); - console_driver.magic = TTY_DRIVER_MAGIC; - console_driver.name = "tty"; - console_driver.name_base = 1; - console_driver.major = TTY_MAJOR; - console_driver.minor_start = 1; - console_driver.num = MAX_NR_CONSOLES; - console_driver.type = TTY_DRIVER_TYPE_CONSOLE; - console_driver.init_termios = tty_std_termios; - console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - console_driver.refcount = &console_refcount; - console_driver.table = console_table; - console_driver.termios = console_termios; - console_driver.termios_locked = console_termios_locked; - - console_driver.open = con_open; - console_driver.write = con_write; - console_driver.write_room = con_write_room; - console_driver.put_char = con_put_char; - console_driver.flush_chars = con_flush_chars; - console_driver.chars_in_buffer = con_chars_in_buffer; - console_driver.ioctl = vt_ioctl; - console_driver.stop = con_stop; - console_driver.start = con_start; - console_driver.throttle = con_throttle; - console_driver.unthrottle = con_unthrottle; - - if (tty_register_driver(&console_driver)) - panic("Couldn't register console driver\n"); - - kmem_start = conswitchp->con_startup (kmem_start, &display_desc); - - timer_table[BLANK_TIMER].fn = blank_screen; - timer_table[BLANK_TIMER].expires = 0; - if (blankinterval) { - timer_table[BLANK_TIMER].expires = jiffies + blankinterval; - timer_active |= 1<con_init determines console size */ - sw = conswitchp; - cons_num = currcons; - sw->con_init (vc_cons[currcons].d); - size_row = cols<<1; - screenbuf_size = rows*size_row; - - vc_scrbuf[currcons] = (unsigned short *) kmem_start; - kmem_start += screenbuf_size; - kmalloced = 0; - vc_init(currcons, currcons); - } - - currcons = fg_console = 0; - - gotoxy(currcons,0,0); - csi_J(currcons, 0); - printable = 1; - update_screen(fg_console); - sw->con_cursor(vc_cons[currcons].d, CM_DRAW); - printable = 1; - - /* If "serdebug" cmd line option was present, don't register for printk */ -#ifdef CONFIG_VT_CONSOLE - if (!serial_debug) - register_console(&vt_console_driver); - printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n", - can_do_color ? "colour":"mono", - display_desc, - cols,rows, - MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); -#endif - init_bh(CONSOLE_BH, console_bh); - return kmem_start; -} - -void vesa_powerdown_screen(void) -{ - int currcons = fg_console; - - timer_active &= ~(1<con_blank(2); - break; - case 1: - case 2: - sw->con_blank(4); - break; - } -} - -void do_blank_screen(int nopowersave) -{ - int currcons; - - if (console_blanked) - return; - - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("blank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - - /* don't blank graphics */ - if (vt_cons[fg_console]->vc_mode == KD_TEXT) { - if (vesa_off_interval && !nopowersave) { - timer_table[BLANK_TIMER].fn = vesa_powerdown_screen; - timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval; - timer_active |= (1<con_blank(1); - if (!nopowersave) - sw->con_blank(vesa_blank_mode + 1); - } - else - hide_cursor(fg_console); - console_blanked = fg_console + 1; -} - -void do_unblank_screen(void) -{ - int currcons; - - if (!console_blanked) - return; - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - timer_table[BLANK_TIMER].fn = blank_screen; - if (blankinterval) { - timer_table[BLANK_TIMER].expires = jiffies + blankinterval; - timer_active |= 1<con_blank (0)) - /* Low-level driver cannot restore -> do it ourselves */ - update_screen( fg_console ); - set_cursor (fg_console); -} - -void update_screen(int new_console) -{ - int currcons = fg_console; - int xx, yy, startx, attr_save; - char buf[256], *bufp; - unsigned short *p; - static int lock = 0; - - if (/* new_console == fg_console || */ lock) - return; - if (!vc_cons_allocated(new_console)) { - /* strange ... */ - printk("update_screen: tty %d not allocated ??\n", new_console+1); - return; - } - lock = 1; - - clear_selection(); - - currcons = fg_console = new_console; - sw->con_cursor (vc_cons[currcons].d, CM_ERASE); - sw->con_switch (vc_cons[new_console].d); - /* Update the screen contents */ - p = video_mem_start; - attr_save = attr; - for (yy = 0; yy < rows; yy++) - { - bufp = buf; - for (startx = xx = 0; xx < cols; xx++) - { - if (attr != ((*p >> 8) & 0xff)) - { - if (bufp > buf) - sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, - yy, startx); - startx = xx; - bufp = buf; - attr = (*p >> 8) & 0xff; - } - *bufp++ = *p++; - if (bufp == buf + sizeof (buf)) - { - sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, - yy, startx); - startx = xx + 1; - bufp = buf; - } - } - if (bufp > buf) - sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, - yy, startx); - } - set_cursor (currcons); - attr = attr_save; - set_leds(); - compute_shiftstate(); - lock = 0; -} - -/* - * If a blank_screen is due to a timer, then a power save is allowed. - * If it is related to console_switching, then avoid vesa_blank(). - */ -static void blank_screen(void) -{ - do_blank_screen(0); -} - -static void unblank_screen(void) -{ - do_unblank_screen(); -} - -/* - * Allocate the console screen memory. - */ -static int con_open(struct tty_struct *tty, struct file * filp) -{ - unsigned int currcons; - int i; - - currcons = MINOR(tty->device) - tty->driver.minor_start; - - i = vc_allocate(currcons); - if (i) - return i; - - vt_cons[currcons]->vc_num = currcons; - tty->driver_data = vt_cons[currcons]; - - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = rows; - tty->winsize.ws_col = cols; - } - - return 0; -} - -/* - * PIO_FONT support. - * - * Currently we only support 8 pixels wide fonts, at a maximum height - * of 32 pixels. Userspace fontdata is stored with 32 bytes reserved - * for each character which is kinda wasty, but this is done in order - * to maintain compatibility with the EGA/VGA fonts. It is upto the - * actual low-level console-driver convert data into its favorite - * format (maybe we should add a `fontoffset' field to the `display' - * structure so we wont have to convert the fontdata all the time. - * /Jes - */ - -#define cmapsz 8192 - -static int set_get_font(char * arg, int set, int ch512) -{ -#ifdef CAN_LOAD_EGA_FONTS - int i, unit, size; - char *charmap; - - if (!arg) - return -EINVAL; - - - size = ch512 ? 2*cmapsz : cmapsz; - - charmap = (char *)kmalloc(size, GFP_USER); - - if (set){ - if (copy_from_user(charmap, arg, size)) { - kfree(charmap); - return -EFAULT; - } - - for (unit = 32; unit > 0; unit--) - for (i = 0; i < (ch512 ? 512 : 256); i++) - if (charmap[32*i+unit-1]) - goto nonzero; - nonzero: - i = conswitchp->con_set_font(vc_cons[fg_console].d, 8, - unit, charmap); - }else{ - memset(charmap, 0, size); - i = conswitchp->con_get_font(vc_cons[fg_console].d, - &unit, &unit, charmap); - if (i == 0 && copy_to_user(arg, charmap, size)) - i = -EFAULT; - } - kfree(charmap); - - return i; -#else - return -EINVAL; -#endif -} - -/* - * Load palette into the EGA/VGA DAC registers. arg points to a colour - * map, 3 bytes per colour, 16 colours, range from 0 to 255. - */ - -static int set_get_cmap(unsigned char *arg, int set) -{ - int i, j, k; - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = - default_red[j]; - vc_cons[i].d->vc_palette[k++] = - default_grn[j]; - vc_cons[i].d->vc_palette[k++] = - default_blu[j]; - } - set_palette(); - } - return 0; -} - -int con_set_cmap (unsigned char *arg) -{ - return set_get_cmap (arg, 1); -} - -int con_get_cmap (unsigned char *arg) -{ - return set_get_cmap (arg, 0); -} - -void reset_palette(int currcons) -{ - int j, k; - for (j = k = 0; j < 16; j++) { - palette[k++] = default_red[j]; - palette[k++] = default_grn[j]; - palette[k++] = default_blu[j]; - } - set_palette() ; -} - -void set_palette(void) -{ - if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS) - conswitchp->con_set_palette(vc_cons[fg_console].d, color_table); -} - -/* - * Load font into the EGA/VGA character generator. arg points to a 8192 - * byte map, 32 bytes per character. Only first H of them are used for - * 8xH fonts (0 < H <= 32). - */ - -int con_set_font (char *arg, int ch512) -{ - int i; - - i = set_get_font (arg,1,ch512); - if ( !i ) { - hashtable_contents_valid = 0; - video_mode_512ch = ch512; - console_charmask = ch512 ? 0x1ff : 0x0ff; - } - return i; -} - -int con_get_font (char *arg) -{ - return set_get_font (arg,0,video_mode_512ch); -} - -/* - * Adjust the screen to fit a font of a certain height - * - * Returns < 0 for error, 0 if nothing changed, and the number - * of lines on the adjusted console if changed. - */ -int con_adjust_height(unsigned long fontheight) -{ - return -EINVAL; -} - -static void set_vesa_blanking(unsigned long arg) -{ - char *argp = (char *)arg + 1; - unsigned int mode; - get_user(mode, argp); - vesa_blank_mode = (mode < 4) ? mode : 0; -} - -unsigned long get_video_num_lines(unsigned int currcons) -{ - return(rows); -} - -unsigned long get_video_num_columns(unsigned int currcons) -{ - return(cols); -} - -unsigned long get_video_size_row(unsigned int currcons) -{ - return(size_row); -} diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.1.86/linux/arch/m68k/kernel/entry.S Mon Dec 1 11:15:39 1997 +++ linux/arch/m68k/kernel/entry.S Thu Feb 12 16:30:12 1998 @@ -37,6 +37,8 @@ #include #include +#include "m68k_defs.h" + .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap) .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) .globl SYMBOL_NAME(ret_from_signal) @@ -63,9 +65,7 @@ ENTRY(reschedule) | save top of frame - pea %sp@ - jbsr SYMBOL_NAME(set_esp0) - addql #4,%sp + movel %sp,%curptr@(TS_ESP0) pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) @@ -98,9 +98,7 @@ GET_CURRENT(%d0) | save top of frame - pea %sp@ - jbsr SYMBOL_NAME(set_esp0) - addql #4,%sp + movel %sp,%curptr@(TS_ESP0) cmpl #NR_syscalls,%d2 jcc badsys @@ -112,6 +110,10 @@ SYMBOL_NAME_LABEL(ret_from_exception) btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel bnes 2f | if so, skip resched, signals + | only allow interrupts when we are really the last one on the + | kernel stack, otherwise stack overflow can occur during + | heavy interupt load + andw #ALLOWINT,%sr tstl SYMBOL_NAME(need_resched) jne SYMBOL_NAME(reschedule) cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals @@ -122,16 +124,8 @@ 5: tstl %curptr@(LTASK_STATE) | state jne SYMBOL_NAME(reschedule) - tstl %curptr@(LTASK_COUNTER) | counter - jeq SYMBOL_NAME(reschedule) - movel %curptr@(LTASK_BLOCKED),%d0 - movel %d0,%d1 | save blocked in d1 for sig handling - notl %d0 - btst #LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF) - jeq 1f - moveq #-1,%d0 | let the debugger see all signals -1: andl %curptr@(LTASK_SIGNAL),%d0 + tstl %curptr@(LTASK_SIGPENDING) jne Lsignal_return 2: RESTORE_ALL @@ -139,7 +133,7 @@ subql #4,%sp | dummy return address SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) - movel %d1,%sp@- + clrl %sp@- bsrl SYMBOL_NAME(do_signal) addql #8,%sp RESTORE_SWITCH_STACK @@ -184,11 +178,6 @@ #endif jhi 2b #endif - /* Let the rest run with interrupts allowed. This is safe since - the kernel never uses a non-standard ipl and this is the outer - level interrupt. */ - andw #ALLOWINT,%sr - /* check if we need to do software interrupts */ movel SYMBOL_NAME(bh_active),%d0 @@ -229,12 +218,26 @@ RESTORE_SWITCH_STACK rts +ENTRY(sys_rt_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr SYMBOL_NAME(do_rt_sigsuspend) + addql #4,%sp + RESTORE_SWITCH_STACK + rts + ENTRY(sys_sigreturn) SAVE_SWITCH_STACK jbsr SYMBOL_NAME(do_sigreturn) RESTORE_SWITCH_STACK rts +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr SYMBOL_NAME(do_rt_sigreturn) + RESTORE_SWITCH_STACK + rts + SYMBOL_NAME_LABEL(resume) /* * Beware - when entering resume, offset of tss is in d1, @@ -251,11 +254,6 @@ /* save sr */ movew %sr,%a0@(LTSS_SR) -#if 0 - /* disable interrupts */ - oriw #0x0700,%sr -#endif - /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ movec %sfc,%d0 movew %d0,%a0@(LTSS_FS) @@ -415,7 +413,7 @@ .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ .long SYMBOL_NAME(sys_chown) - .long SYMBOL_NAME(sys_break) + .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ @@ -429,11 +427,11 @@ .long SYMBOL_NAME(sys_fstat) .long SYMBOL_NAME(sys_pause) .long SYMBOL_NAME(sys_utime) /* 30 */ - .long SYMBOL_NAME(sys_stty) - .long SYMBOL_NAME(sys_gtty) + .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ .long SYMBOL_NAME(sys_access) .long SYMBOL_NAME(sys_nice) - .long SYMBOL_NAME(sys_ftime) /* 35 */ + .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */ .long SYMBOL_NAME(sys_sync) .long SYMBOL_NAME(sys_kill) .long SYMBOL_NAME(sys_rename) @@ -442,7 +440,7 @@ .long SYMBOL_NAME(sys_dup) .long SYMBOL_NAME(sys_pipe) .long SYMBOL_NAME(sys_times) - .long SYMBOL_NAME(sys_prof) + .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ .long SYMBOL_NAME(sys_setgid) .long SYMBOL_NAME(sys_getgid) @@ -450,14 +448,14 @@ .long SYMBOL_NAME(sys_geteuid) .long SYMBOL_NAME(sys_getegid) /* 50 */ .long SYMBOL_NAME(sys_acct) - .long SYMBOL_NAME(sys_phys) - .long SYMBOL_NAME(sys_lock) + .long SYMBOL_NAME(sys_ni_syscall) /* old phys syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ .long SYMBOL_NAME(sys_ioctl) .long SYMBOL_NAME(sys_fcntl) /* 55 */ - .long SYMBOL_NAME(sys_mpx) + .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ .long SYMBOL_NAME(sys_setpgid) - .long SYMBOL_NAME(sys_ulimit) - .long SYMBOL_NAME(sys_olduname) + .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_umask) /* 60 */ .long SYMBOL_NAME(sys_chroot) .long SYMBOL_NAME(sys_ustat) @@ -496,7 +494,7 @@ .long SYMBOL_NAME(sys_fchown) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) - .long SYMBOL_NAME(sys_profil) + .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ .long SYMBOL_NAME(sys_statfs) .long SYMBOL_NAME(sys_fstatfs) /* 100 */ .long SYMBOL_NAME(sys_ioperm) @@ -507,7 +505,7 @@ .long SYMBOL_NAME(sys_newstat) .long SYMBOL_NAME(sys_newlstat) .long SYMBOL_NAME(sys_newfstat) - .long SYMBOL_NAME(sys_uname) + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */ .long SYMBOL_NAME(sys_vhangup) .long SYMBOL_NAME(sys_idle) @@ -568,9 +566,19 @@ .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) + .long SYMBOL_NAME(sys_setresgid) /* 170 */ + .long SYMBOL_NAME(sys_getresgid) .long SYMBOL_NAME(sys_prctl) - .long SYMBOL_NAME(sys_pread) + .long SYMBOL_NAME(sys_rt_sigreturn) + .long SYMBOL_NAME(sys_rt_sigaction) + .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */ + .long SYMBOL_NAME(sys_rt_sigpending) + .long SYMBOL_NAME(sys_rt_sigtimedwait) + .long SYMBOL_NAME(sys_rt_sigqueueinfo) + .long SYMBOL_NAME(sys_rt_sigsuspend) + .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) + .long SYMBOL_NAME(sys_lchown); .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S --- v2.1.86/linux/arch/m68k/kernel/head.S Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/kernel/head.S Thu Feb 12 16:30:12 1998 @@ -14,6 +14,7 @@ ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa +** 95/11/18 Richard Hirst: Added MVME166 support ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with ** Magnum- and FX-alternate ram ** @@ -72,8 +73,7 @@ #include .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt) -.globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa) -.globl SYMBOL_NAME(is_hades) +.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr) .globl SYMBOL_NAME(m68k_pgtable_cachemode) .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir) @@ -145,6 +145,7 @@ #define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab #define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab +#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab #define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab #define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab @@ -162,6 +163,7 @@ .long BOOTINFOV_MAGIC .long MACH_AMIGA, AMIGA_BOOTI_VERSION .long MACH_ATARI, ATARI_BOOTI_VERSION + .long MACH_MVME16x, MVME16x_BOOTI_VERSION .long 0 1: jra SYMBOL_NAME(_start) @@ -249,33 +251,25 @@ #ifdef CONFIG_ATARI is_not_atari(Lnotypetest) - moveq #0,%d3 /* base addr for others: 0x00000000 */ - moveq #0,%d2 /* no Hades */ - movec %d3,%vbr - lea %pc@(Ltest_berr),%a0 - movel %a0,0x8 - movel %sp,%a0 - moveb 0x0,%d1 - clrb 0x0 - nop - moveb %d1,0x0 - nop - tstb 0x00ff82fe - nop - movel #0xff000000,%d3 /* Medusa base addr: 0xff000000 */ - tstb 0xb0000000 - nop - movel #0xff000000,%d2 /* Computer is a Hades */ - moveq #0,%d3 -Ltest_berr: - movel %a0,%sp - lea %pc@(SYMBOL_NAME(is_hades)),%a0 - movel %d2,%a0@ - lea %pc@(SYMBOL_NAME(is_medusa)),%a0 - movel %d3,%a0@ - lea %pc@(Liobase),%a0 - movel %d2,%a0@ /* On a Hades the iobase must be set - before opening the serial port. */ + /* get special machine type (Medusa/Hades/AB40) */ + moveq #0,%d3 /* default if tag doesn't exist */ + movew #BI_ATARI_MCH_TYPE,%d0 + jbsr Lget_bi_record + tstl %d0 + jbmi 1f + movel %a0@,%d3 +1: + /* %d3 is not clobbered until Atari page tables are set up, + * where it is used again. */ + + /* On the Hades, the iobase must be set up before opening the + * serial port. There are no I/O regs at 0x00ffxxxx at all. */ + moveq #0,%d0 + cmpl #ATARI_MACH_HADES,%d3 + jbne 1f + movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */ +1: lea %pc@(Liobase),%a0 + movel %d0,%a0@ Lnotypetest: #endif @@ -543,10 +537,15 @@ area. */ - movel %pc@(is_medusa),%d3 - bne 1f - movel %pc@(is_hades),%d3 -1: + /* I/O base addr for non-Medusa, non-Hades: 0x00000000 */ + moveq #0,%d0 + cmpl #ATARI_MACH_MEDUSA,%d3 + jbeq 2f + cmpl #ATARI_MACH_HADES,%d3 + jbne 1f +2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */ +1: movel %d0,%d3 + /* Let the root table point to the new pointer table */ lea %a4@(PTR_TABLE_SIZE<<2),%a4 movel %a4,%a0 @@ -616,6 +615,30 @@ Lnotatari: #endif +#if defined(CONFIG_MVME16x) + is_not_mvme16x(Lnot16x) + + /* Get pointer to board ID data */ + movel %d2,%sp@- + .long 0x4e4f0070 /* trap 0x70 - .BRD_ID */ + movel %sp@+,%d2 + lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0 + movel %d2,%a0@ + + /* + * On MVME16x we have already created kernel page tables for + * 4MB of RAM at address 0, so now need to do a transparent + * mapping of the top of memory space. Make it 0.5GByte for now. + */ + + movel #0xe01f0000,%d2 /* logical address base */ + orw #0xa040,%d2 /* add in magic bits */ + .long 0x4e7b2005 /* movec d2,ittr1 */ + .long 0x4e7b2007 /* movec d2,dttr1 */ + +Lnot16x: +#endif + /* * Setup a transparent mapping of the physical memory we are executing in. * @@ -810,6 +833,26 @@ Lmapphysnotatari: #endif +#if defined(CONFIG_MVME16x) + is_not_mvme16x(Lmapphysnot16x) + /* + * save physaddr of phys mem in register a3 + */ + moveq #'L',%d7 + jbsr Lserial_putc + + .word 0xf4d8 /* CINVA I/D */ + .word 0xf518 /* pflusha */ + .long 0x4e7bd807 /* movec a5,srp */ + .long 0x4e7bd806 /* movec a5,urp */ + movel #(TC_ENABLE+TC_PAGE4K),%d0 + .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */ + jra LdoneMMUenable /* branch to continuation of startup */ + +Lmapphysnot16x: + +#endif + LdoneMMUenable: /* @@ -833,30 +876,6 @@ putc('N') -#if 0 - putr() - lea SYMBOL_NAME(kernel_pmd_table),%a0 - moveq #63,%d0 -1: moveq #7,%d1 - putn(%a0) - putc(':') - putc(' ') -2: putn(%a0@+) - dbra %d1,2b - putr() - dbra %d0,1b - putr() - movel SYMBOL_NAME(kpt),%a0 - moveq #639,%d0 -1: moveq #7,%d1 - putn(%a0) - putc(':') - putc(' ') -2: putn(%a0@+) - dbra %d1,2b - putr() - dbra %d0,1b -#endif /* * Enable caches */ @@ -899,6 +918,7 @@ /* jump to the kernel start */ putr() + subl %a6,%a6 /* clear a6 for gdb */ jbsr SYMBOL_NAME(start_kernel) /* @@ -1048,6 +1068,13 @@ */ Lserial_putc: moveml %a0/%a1,%sp@- +#if defined(CONFIG_MVME16x) + cmpil #MACH_MVME16x,%d4 + jne 2f + moveb %d7,%sp@- + .long 0x4e4f0020 +2: +#endif #ifdef CONFIG_AMIGA cmpil #MACH_AMIGA,%d4 jne 2f @@ -1130,6 +1157,7 @@ moveml %sp@+,%d0-%d2/%d7 rts +#if 0 Lshowtest: moveml %a0/%d7,%sp@- putc('A') @@ -1158,7 +1186,7 @@ putr() moveml %sp@+,%a0/%d7 rts - +#endif .data .even Lcustom: @@ -1169,9 +1197,7 @@ .long 0 SYMBOL_NAME_LABEL(availmem) .long 0 -SYMBOL_NAME_LABEL(is_medusa) - .long 0 -SYMBOL_NAME_LABEL(is_hades) - .long 0 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) + .long 0 +SYMBOL_NAME_LABEL(mvme_bdid_ptr) .long 0 diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c --- v2.1.86/linux/arch/m68k/kernel/ints.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/kernel/ints.c Thu Feb 12 16:30:12 1998 @@ -53,7 +53,7 @@ unsigned int local_irq_count[NR_CPUS]; -int __m68k_bh_counter; +unsigned int local_bh_count[NR_CPUS]; static void dummy_enable_irq(unsigned int irq); static void dummy_disable_irq(unsigned int irq); @@ -214,7 +214,7 @@ { if (vec >= VEC_INT1 && vec <= VEC_INT7) { vec -= VEC_SPUR; - kstat.interrupts[vec]++; + kstat.irqs[0][vec]++; irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); } else { if (mach_process_int) @@ -233,7 +233,7 @@ if (mach_default_handler) { for (i = 0; i < SYS_IRQS; i++) { len += sprintf(buf+len, "auto %2d: %10u ", i, - i ? kstat.interrupts[i] : num_spurious); + i ? kstat.irqs[0][i] : num_spurious); if (irq_list[i].flags & IRQ_FLG_LOCK) len += sprintf(buf+len, "L "); else diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/m68k_defs.c linux/arch/m68k/kernel/m68k_defs.c --- v2.1.86/linux/arch/m68k/kernel/m68k_defs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/kernel/m68k_defs.c Thu Feb 12 16:30:12 1998 @@ -0,0 +1,23 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n#define " #sym " %0" : : "i" (val)) + +int main(void) +{ + DEFINE(TS_TSS, offsetof(struct task_struct, tss)); + DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0)); + DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp)); + return 0; +} diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.1.86/linux/arch/m68k/kernel/m68k_ksyms.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/kernel/m68k_ksyms.c Thu Feb 12 16:30:12 1998 @@ -26,16 +26,15 @@ /* platform dependent support */ -EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(m68k_machtype); EXPORT_SYMBOL(m68k_cputype); EXPORT_SYMBOL(m68k_is040or060); EXPORT_SYMBOL(cache_push); -EXPORT_SYMBOL(cache_push_v); EXPORT_SYMBOL(cache_clear); EXPORT_SYMBOL(mm_vtop); EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); +EXPORT_SYMBOL(kernel_map); EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); @@ -43,7 +42,7 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(local_irq_count); -EXPORT_SYMBOL(__m68k_bh_counter); +EXPORT_SYMBOL(local_bh_count); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); @@ -55,6 +54,7 @@ EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.1.86/linux/arch/m68k/kernel/process.c Sat Aug 16 09:51:07 1997 +++ linux/arch/m68k/kernel/process.c Thu Feb 12 16:30:12 1998 @@ -65,7 +65,7 @@ current->priority = -100; current->counter = -100; for (;;){ - if (!resched_needed()) + if (!need_resched) #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) /* block out HSYNC on the atari (falcon) */ __asm__("stop #0x2200" : : : "cc"); @@ -113,17 +113,14 @@ printk("USP: %08lx\n", rdusp()); } -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - void flush_thread(void) { + unsigned long zero = 0; set_fs(USER_DS); - current->tss.fs = USER_DS; + current->tss.fs = __USER_DS; + asm volatile (".chip 68k/68881\n\t" + "frestore %0@\n\t" + ".chip 68k" : : "a" (&zero)); } /* @@ -160,10 +157,6 @@ return ret; } -void release_thread(struct task_struct *dead_task) -{ -} - int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { @@ -190,13 +183,12 @@ * Must save the current SFC/DFC value, NOT the value when * the parent was last descheduled - RGH 10-08-96 */ - p->tss.fs = get_fs(); + p->tss.fs = get_fs().seg; /* Copy the current fpu state */ asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory"); - if((!CPU_IS_060 && p->tss.fpstate[0]) || - (CPU_IS_060 && p->tss.fpstate[2])) + if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2]) asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0]) @@ -215,7 +207,7 @@ /* First dump the fpu context to avoid protocol violation. */ asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if((!CPU_IS_060 && !fpustate[0]) || (CPU_IS_060 && !fpustate[2])) + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) return 0; asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c --- v2.1.86/linux/arch/m68k/kernel/ptrace.c Sat Aug 16 09:51:07 1997 +++ linux/arch/m68k/kernel/ptrace.c Thu Feb 12 16:30:12 1998 @@ -10,7 +10,6 @@ * this archive for more details. */ -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include /* * does not yet catch signals sent when the child dies. @@ -439,7 +439,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; @@ -477,7 +477,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; child->flags &= ~PF_TRACESYS; tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); @@ -494,7 +494,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); @@ -509,6 +509,59 @@ goto out; } + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + if (i == PT_SR) + tmp >>= 16; + if (put_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + goto out; + } + data += sizeof(long); + } + ret = 0; + goto out; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + goto out; + } + if (i == PT_SR) { + tmp &= SR_MASK; + tmp <<= 16; + tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + put_reg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + goto out; + } + + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + ret = 0; + if (copy_to_user((void *)data, &child->tss.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + goto out; + } + + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + ret = 0; + if (copy_from_user(&child->tss.fp, (void *)data, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + goto out; + } + default: ret = -EIO; goto out; @@ -533,9 +586,10 @@ * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ - if (current->exit_code) - current->signal |= (1 << (current->exit_code - 1)); - current->exit_code = 0; + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } out: unlock_kernel(); } diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.1.86/linux/arch/m68k/kernel/setup.c Mon Jun 16 16:35:53 1997 +++ linux/arch/m68k/kernel/setup.c Thu Feb 12 16:30:12 1998 @@ -36,15 +36,13 @@ #include #endif -u_long m68k_machtype; -u_long m68k_cputype; -u_long m68k_fputype; -u_long m68k_mmutype; +unsigned long m68k_machtype; +unsigned long m68k_cputype; +unsigned long m68k_fputype; +unsigned long m68k_mmutype; int m68k_is040or060 = 0; -char m68k_debug_device[6] = ""; - extern int end; extern unsigned long availmem; @@ -56,6 +54,8 @@ static char m68k_command_line[CL_SIZE]; char saved_command_line[CL_SIZE]; +char m68k_debug_device[6] = ""; + void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata; /* machine dependent keyboard functions */ int (*mach_keyb_init) (void) __initdata; @@ -74,23 +74,34 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); -struct fb_info *(*mach_fb_init)(long *) __initdata; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -void (*mach_video_setup) (char *, int *) __initdata; -#ifdef CONFIG_BLK_DEV_FD -int (*mach_floppy_init) (void) __initdata = NULL; +#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; void (*mach_floppy_eject) (void) = NULL; #endif +#ifdef CONFIG_HEARTBEAT +void (*mach_heartbeat) (int) = NULL; +#endif + +extern void base_trap_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +int mach_sysrq_key = -1; +int mach_sysrq_shift_state = 0; +int mach_sysrq_shift_mask = 0; +char *mach_sysrq_xlate = NULL; +#endif extern int amiga_parse_bootinfo(const struct bi_record *); extern int atari_parse_bootinfo(const struct bi_record *); +extern int mac_parse_bootinfo(const struct bi_record *); extern void config_amiga(void); extern void config_atari(void); extern void config_mac(void); extern void config_sun3(void); extern void config_apollo(void); +extern void config_mvme16x(void); #define MASK_256K 0xfffc0000 @@ -132,6 +143,8 @@ unknown = amiga_parse_bootinfo(record); else if (MACH_IS_ATARI) unknown = atari_parse_bootinfo(record); + else if (MACH_IS_MAC) + unknown = mac_parse_bootinfo(record); else unknown = 1; } @@ -145,7 +158,6 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { - unsigned long memory_start, memory_end; extern int _etext, _edata, _end; int i; char *p, *q; @@ -158,19 +170,15 @@ else if (CPU_IS_060) m68k_is040or060 = 6; + base_trap_init(); + /* 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)); } - memory_start = availmem; - memory_end = 0; - - for (i = 0; i < m68k_num_memory; i++) - memory_end += m68k_memory[i].size & MASK_256K; - - init_task.mm->start_code = 0; + init_task.mm->start_code = PAGE_OFFSET; init_task.mm->end_code = (unsigned long) &_etext; init_task.mm->end_data = (unsigned long) &_edata; init_task.mm->brk = (unsigned long) &_end; @@ -190,6 +198,15 @@ if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; i = 1; } +#ifdef CONFIG_ATARI + /* This option must be parsed very early */ + if (!strncmp( p, "switches=", 9 )) { + extern void atari_switches_setup( const char *, int ); + atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? + (q - (p+9)) : strlen(p+9) ); + i = 1; + } +#endif if (i) { /* option processed, delete it */ @@ -202,9 +219,6 @@ } } - *memory_start_p = memory_start; - *memory_end_p = memory_end; - switch (m68k_machtype) { #ifdef CONFIG_AMIGA case MACH_AMIGA: @@ -231,6 +245,11 @@ config_apollo(); break; #endif +#ifdef CONFIG_MVME16x + case MACH_MVME16x: + config_mvme16x(); + break; +#endif default: panic ("No configuration setup"); } @@ -241,6 +260,11 @@ initrd_end = initrd_start + m68k_ramdisk.size; } #endif + + *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; } int get_cpuinfo(char * buffer) @@ -337,15 +361,7 @@ return(len); } -#ifdef CONFIG_BLK_DEV_FD -__initfunc(int floppy_init(void)) -{ - if (mach_floppy_init) - return mach_floppy_init(); - else - return 0; -} - +#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) __initfunc(void floppy_setup(char *str, int *ints)) { if (mach_floppy_setup) @@ -373,8 +389,16 @@ *year = *mon = *day = *hour = *min = *sec = 0; } -__initfunc(void video_setup (char *options, int *ints)) +void check_bugs(void) { - if (mach_video_setup) - mach_video_setup (options, ints); +#ifndef CONFIG_FPU_EMU + if (m68k_fputype == 0) { + printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " + "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); + printk( KERN_EMERG "Upgrade your hardware or join the FPU " + "emulation project\n" ); + printk( KERN_EMERG "(see http://no-fpu.linux-m68k.org)\n" ); + panic( "no FPU" ); + } +#endif } diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.1.86/linux/arch/m68k/kernel/signal.c Sat Aug 16 09:51:07 1997 +++ linux/arch/m68k/kernel/signal.c Thu Feb 12 16:30:12 1998 @@ -12,13 +12,15 @@ * Linux/m68k support by Hamish Macdonald * * 68060 fixes by Jesper Skov + * + * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab */ /* * ++roman (07/09/96): implemented signal stacks (specially for tosemu on * Atari :-) Current limitation: Only one sigstack can be active at one time. - * If a second signal with SA_STACK set arrives while working on a sigstack, - * SA_STACK is ignored. This behaviour avoids lots of trouble with nested + * If a second signal with SA_ONSTACK set arrives while working on a sigstack, + * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested * signal handlers! */ @@ -30,22 +32,19 @@ #include #include #include +#include #include #include #include #include +#include -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) - -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); - -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); const int frame_extra_sizes[16] = { 0, @@ -67,54 +66,232 @@ }; /* - * atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int do_sigsuspend(struct pt_regs *regs) { - unsigned long oldmask = current->blocked; - unsigned long newmask = regs->d3; + old_sigset_t mask = regs->d3; + sigset_t saveset; + + mask &= _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t *unewset = (sigset_t *)regs->d1; + size_t sigsetsize = (size_t)regs->d2; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); - current->blocked = newmask & _BLOCKABLE; regs->d0 = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(oldmask, regs)) + if (do_signal(&saveset, regs)) return -EINTR; } } +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ + char *pretcode; + int sig; + int code; + struct sigcontext *psc; + char retcode[8]; + unsigned long extramask[_NSIG_WORDS-1]; + struct sigcontext sc; +}; + +struct rt_sigframe +{ + char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + char retcode[8]; +}; + + static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ -asmlinkage int do_sigreturn(unsigned long __unused) +static inline void restore_fpu_state(struct sigcontext *sc) { - struct sigcontext context; - struct pt_regs *regs; - struct switch_stack *sw; - int fsize = 0; - int formatvec = 0; - unsigned long fp; - unsigned long usp = rdusp(); + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + /* Verify the frame format. */ + if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) + goto badframe; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) + goto badframe; + if (m68k_fputype & FPU_68882 && + !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) + goto badframe; + } else if (CPU_IS_040) { + if (!(sc->sc_fpstate[1] == 0x00 || + sc->sc_fpstate[1] == 0x28 || + sc->sc_fpstate[1] == 0x60)) + goto badframe; + } else if (CPU_IS_060) { + if (!(sc->sc_fpstate[3] == 0x00 || + sc->sc_fpstate[3] == 0x60 || + sc->sc_fpstate[3] == 0xe0)) + goto badframe; + } else + goto badframe; -#if 0 - printk("sys_sigreturn, usp=%08x\n", (unsigned) usp); -#endif + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %0,%/fp0-%/fp1\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); + } + __asm__ volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (*sc->sc_fpstate)); + return; + +badframe: + do_exit(SIGSEGV); +} - /* get stack frame pointer */ - sw = (struct switch_stack *) &__unused; - regs = (struct pt_regs *) (sw + 1); +#define FPCONTEXT_SIZE 216 +#define uc_fpstate uc_filler[0] +#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] +#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] - /* get previous context (including pointer to possible extra junk) */ - if (copy_from_user(&context,(void *)usp, sizeof(context))) +static inline void rt_restore_fpu_state(struct ucontext *uc) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + fpregset_t fpregs; + + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) + goto badframe; + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + if (!CPU_IS_060) + context_size = fpstate[1]; + /* Verify the frame format. */ + if (!CPU_IS_060 && (fpstate[0] != fpu_version)) + goto badframe; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(context_size == 0x18 || context_size == 0xb4)) + goto badframe; + if (m68k_fputype & FPU_68882 && + !(context_size == 0x38 || context_size == 0xd4)) + goto badframe; + } else if (CPU_IS_040) { + if (!(context_size == 0x00 || + context_size == 0x28 || + context_size == 0x60)) + goto badframe; + } else if (CPU_IS_060) { + if (!(fpstate[3] == 0x00 || + fpstate[3] == 0x60 || + fpstate[3] == 0xe0)) + goto badframe; + } else + goto badframe; + if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, + sizeof(fpregs))) + goto badframe; + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %0,%/fp0-%/fp7\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*fpregs.f_fpregs), + "m" (fpregs.f_pcr)); + } + if (context_size && + __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, + context_size)) goto badframe; + __asm__ volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (*fpstate)); + return; - fp = usp + sizeof (context); +badframe: + do_exit(SIGSEGV); +} - /* restore signal mask */ - current->blocked = context.sc_mask & _BLOCKABLE; +static inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp) +{ + int fsize, formatvec; + struct sigcontext context; + /* get previous context */ + if (copy_from_user(&context, usc, sizeof(context))) + goto badframe; + /* restore passed registers */ - regs->d0 = context.sc_d0; regs->d1 = context.sc_d1; regs->a0 = context.sc_a0; regs->a1 = context.sc_a1; @@ -125,43 +302,8 @@ formatvec = context.sc_formatvec; regs->format = formatvec >> 12; regs->vector = formatvec & 0xfff; - if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){ - /* Verify the frame format. */ - if (!CPU_IS_060 && (context.sc_fpstate[0] != fpu_version)) - goto badframe; - if (m68k_fputype & FPU_68881) - { - if (context.sc_fpstate[1] != 0x18 - && context.sc_fpstate[1] != 0xb4) - goto badframe; - } - else if (m68k_fputype & FPU_68882) - { - if (context.sc_fpstate[1] != 0x38 - && context.sc_fpstate[1] != 0xd4) - goto badframe; - } - else if (m68k_fputype & FPU_68040) - { - if (!(context.sc_fpstate[1] == 0x00 || - context.sc_fpstate[1] == 0x28 || - context.sc_fpstate[1] == 0x60)) - goto badframe; - } - else if (m68k_fputype & FPU_68060) - { - if (!(context.sc_fpstate[3] == 0x00 || - context.sc_fpstate[3] == 0x60 || - context.sc_fpstate[3] == 0xe0)) - goto badframe; - } - __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t" - "fmoveml %1,%/fpcr/%/fpsr/%/fpiar" - : /* no outputs */ - : "m" (*context.sc_fpregs), - "m" (*context.sc_fpcntl)); - } - __asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate)); + + restore_fpu_state(&context); fsize = frame_extra_sizes[regs->format]; if (fsize < 0) { @@ -174,14 +316,13 @@ goto badframe; } - if (context.sc_usp != fp+fsize) - current->flags &= ~PF_ONSIGSTK; - /* OK. Make room on the supervisor stack for the extra junk, * if necessary. */ if (fsize) { + struct switch_stack *sw = (struct switch_stack *)regs - 1; + regs->d0 = context.sc_d0; #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) __asm__ __volatile__ (" movel %0,%/a0\n\t" @@ -215,127 +356,494 @@ goto badframe; } + return context.sc_d0; + +badframe: + do_exit(SIGSEGV); +} + +static inline int +rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, + struct ucontext *uc) +{ + int fsize, temp; + greg_t *gregs = uc->uc_mcontext.gregs; + + __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + __get_user(regs->d0, &gregs[0]); + __get_user(regs->d1, &gregs[1]); + __get_user(regs->d2, &gregs[2]); + __get_user(regs->d3, &gregs[3]); + __get_user(regs->d4, &gregs[4]); + __get_user(regs->d5, &gregs[5]); + __get_user(sw->d6, &gregs[6]); + __get_user(sw->d7, &gregs[7]); + __get_user(regs->a0, &gregs[8]); + __get_user(regs->a1, &gregs[9]); + __get_user(regs->a2, &gregs[10]); + __get_user(sw->a3, &gregs[11]); + __get_user(sw->a4, &gregs[12]); + __get_user(sw->a5, &gregs[13]); + __get_user(sw->a6, &gregs[14]); + __get_user(temp, &gregs[15]); + wrusp(temp); + __get_user(regs->pc, &gregs[16]); + __get_user(temp, &gregs[17]); + regs->sr = (regs->sr & 0xff00) | (temp & 0xff); + regs->orig_d0 = -1; /* disable syscall checks */ + __get_user(temp, &uc->uc_formatvec); + regs->format = temp >> 12; + regs->vector = temp & 0xfff; + + rt_restore_fpu_state(uc); + + fsize = frame_extra_sizes[regs->format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#if DEBUG + printk("user process returning with weird frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + if (fsize) { +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + (" movel %0,%/a0\n\t" + " subl %1,%/a0\n\t" /* make room on stack */ + " movel %/a0,%/sp\n\t" /* set stack pointer */ + /* move switch_stack and pt_regs */ + "1: movel %0@+,%/a0@+\n\t" + " dbra %2,1b\n\t" + " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ + " lsrl #2,%1\n\t" + " subql #1,%1\n\t" + "2: movesl %4@+,%2\n\t" + "3: movel %2,%/a0@+\n\t" + " dbra %1,2b\n\t" + " bral " SYMBOL_NAME_STR(ret_from_signal) "\n" + "4:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,4b\n" + " .long 3b,4b\n" + ".previous" + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (&uc->uc_extra) + : "a0"); +#undef frame_offset + /* + * If we ever get here an exception occured while + * building the above stack-frame. + */ + goto badframe; + } + return regs->d0; + badframe: do_exit(SIGSEGV); } +asmlinkage int do_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct sigframe *frame = (struct sigframe *)(usp - 24); + sigset_t set; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.sc_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + current->blocked = set; + recalc_sigpending(current); + + return restore_sigcontext(regs, &frame->sc, frame + 1); + +badframe: + do_exit(SIGSEGV); +} + +asmlinkage int do_rt_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); + sigset_t set; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + current->blocked = set; + recalc_sigpending(current); + + return rt_restore_ucontext(regs, sw, &frame->uc); + +badframe: + do_exit(SIGSEGV); +} + /* - * Set up a signal frame... - * - * This routine is somewhat complicated by the fact that if the - * kernel may be entered by an exception other than a system call; - * e.g. a bus error or other "bad" exception. If this is the case, - * then *all* the context on the kernel stack frame must be saved. - * - * For a large number of exceptions, the stack frame format is the same - * as that which will be created when the process traps back to the kernel - * when finished executing the signal handler. In this case, nothing - * must be done. This is exception frame format "0". For exception frame - * formats "2", "9", "A" and "B", the extra information on the frame must - * be saved. This information is saved on the user stack and restored - * when the signal handler is returned. - * - * The format of the user stack when executing the signal handler is: - * - * usp -> RETADDR (points to code below) - * signum (parm #1) - * sigcode (parm #2 ; vector number) - * scp (parm #3 ; sigcontext pointer, pointer to #1 below) - * code1 (addaw #20,sp) ; pop parms and code off stack - * code2 (moveq #119,d0; trap #0) ; sigreturn syscall - * #1| oldmask - * | old usp - * | d0 (first saved reg) - * | d1 - * | a0 - * | a1 - * | sr (saved status register) - * | pc (old pc; one to return to) - * | forvec (format and vector word of old supervisor stack frame) - * | floating point context - * - * These are optionally followed by some extra stuff, depending on the - * stack frame interrupted. This is 1 longword for format "2", 3 - * longwords for format "9", 6 longwords for format "A", and 21 - * longwords for format "B". + * Set up a signal frame. */ -#define UFRAME_SIZE(fs) (sizeof(struct sigcontext)/4 + 6 + fs/4) +static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) +{ + __asm__ volatile (".chip 68k/68881\n\t" + "fsave %0\n\t" + ".chip 68k" + : : "m" (*sc->sc_fpstate) : "memory"); + + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + fpu_version = sc->sc_fpstate[0]; + if (CPU_IS_020_OR_030 && + regs->vector >= (VEC_FPBRUC * 4) && + regs->vector <= (VEC_FPNAN * 4)) { + /* Clear pending exception in 68882 idle frame */ + if (*(unsigned short *) sc->sc_fpstate == 0x1f38) + sc->sc_fpstate[0x38] |= 1 << 3; + } + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %/fp0-%/fp1,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*sc->sc_fpregs), + "m" (*sc->sc_fpcntl) + : "memory"); + } +} -static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs, - int signr, unsigned long oldmask) +static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) { - struct sigcontext context; - unsigned long *frame, *tframe; + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + + __asm__ volatile (".chip 68k/68881\n\t" + "fsave %0\n\t" + ".chip 68k" + : : "m" (*fpstate) : "memory"); + + __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + fpregset_t fpregs; + if (!CPU_IS_060) + context_size = fpstate[1]; + fpu_version = fpstate[0]; + if (CPU_IS_020_OR_030 && + regs->vector >= (VEC_FPBRUC * 4) && + regs->vector <= (VEC_FPNAN * 4)) { + /* Clear pending exception in 68882 idle frame */ + if (*(unsigned short *) fpstate == 0x1f38) + fpstate[0x38] |= 1 << 3; + } + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*fpregs.f_fpregs), + "m" (fpregs.f_pcr) + : "memory"); + copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs)); + } + if (context_size) + copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, + context_size); +} + +static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + sc->sc_mask = mask; + sc->sc_usp = rdusp(); + sc->sc_d0 = regs->d0; + sc->sc_d1 = regs->d1; + sc->sc_a0 = regs->a0; + sc->sc_a1 = regs->a1; + sc->sc_sr = regs->sr; + sc->sc_pc = regs->pc; + sc->sc_formatvec = regs->format << 12 | regs->vector; + save_fpu_state(sc, regs); +} + +static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t *gregs = uc->uc_mcontext.gregs; + + __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + __put_user(regs->d0, &gregs[0]); + __put_user(regs->d1, &gregs[1]); + __put_user(regs->d2, &gregs[2]); + __put_user(regs->d3, &gregs[3]); + __put_user(regs->d4, &gregs[4]); + __put_user(regs->d5, &gregs[5]); + __put_user(sw->d6, &gregs[6]); + __put_user(sw->d7, &gregs[7]); + __put_user(regs->a0, &gregs[8]); + __put_user(regs->a1, &gregs[9]); + __put_user(regs->a2, &gregs[10]); + __put_user(sw->a3, &gregs[11]); + __put_user(sw->a4, &gregs[12]); + __put_user(sw->a5, &gregs[13]); + __put_user(sw->a6, &gregs[14]); + __put_user(rdusp(), &gregs[15]); + __put_user(regs->pc, &gregs[16]); + __put_user(regs->sr, &gregs[17]); + __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); + rt_save_fpu_state(uc, regs); +} + +static inline void push_cache (unsigned long vaddr) +{ + /* + * Using the old cache_push_v() was really a big waste. + * + * What we are trying to do is to flush 8 bytes to ram. + * Flushing 2 cache lines of 16 bytes is much cheaper than + * flushing 1 or 2 pages, as previously done in + * cache_push_v(). + * Jes + */ + if (CPU_IS_040) { + unsigned long temp; + + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr,%0\n\t" + ".chip 68k" + : "=r" (temp) + : "a" (vaddr)); + + temp &= PAGE_MASK; + temp |= vaddr & ~PAGE_MASK; + + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + if (((vaddr + 8) ^ vaddr) & ~15) { + if (((vaddr + 8) ^ vaddr) & PAGE_MASK) + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr,%0\n\t" + ".chip 68k" + : "=r" (temp) + : "a" (vaddr + 8)); + + temp &= PAGE_MASK; + temp |= (vaddr + 8) & ~PAGE_MASK; + + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + } + } + else if (CPU_IS_060) { + unsigned long temp; + __asm__ __volatile__ (".chip 68060\n\t" + "plpar (%0)\n\t" + ".chip 68k" + : "=a" (temp) + : "0" (vaddr)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + if (((vaddr + 8) ^ vaddr) & ~15) { + if (((vaddr + 8) ^ vaddr) & PAGE_MASK) + __asm__ __volatile__ (".chip 68060\n\t" + "plpar (%0)\n\t" + ".chip 68k" + : "=a" (temp) + : "0" (vaddr + 8)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + } + } + else { + /* + * 68030/68020 have no writeback cache; + * still need to clear icache. + * Note that vaddr is guaranteed to be long word aligned. + */ + unsigned long temp; + asm volatile ("movec %%cacr,%0" : "=r" (temp)); + temp += 4; + asm volatile ("movec %0,%%caar\n\t" + "movec %1,%%cacr" + : : "r" (vaddr), "r" (temp)); + asm volatile ("movec %0,%%caar\n\t" + "movec %1,%%cacr" + : : "r" (vaddr + 4), "r" (temp)); + } +} + +static void setup_frame (int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; int fsize = frame_extra_sizes[regs->format]; + struct sigcontext context; if (fsize < 0) { +#ifdef DEBUG printk ("setup_frame: Unknown frame format %#x\n", regs->format); - do_exit(SIGSEGV); +#endif + goto segv_and_exit; } - frame = (unsigned long *)rdusp(); - if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) { - frame = (unsigned long *)sa->sa_restorer; + frame = (struct sigframe *)((rdusp() - sizeof(*frame) - fsize) & -8); + + if (!(current->flags & PF_ONSIGSTK) && (ka->sa.sa_flags & SA_ONSTACK)) { + frame = (struct sigframe *)(((unsigned long)ka->sa.sa_restorer + - sizeof(*frame) - fsize) & -8); current->flags |= PF_ONSIGSTK; } - frame -= UFRAME_SIZE(fsize); if (fsize) { - if (copy_to_user (frame + UFRAME_SIZE(0), regs + 1, fsize)) - do_exit(SIGSEGV); + if (copy_to_user (frame + 1, regs + 1, fsize)) + goto segv_and_exit; regs->stkadj = fsize; } -/* set up the "normal" stack seen by the signal handler */ - tframe = frame; + __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + + __put_user(regs->vector, &frame->code); + __put_user(&frame->sc, &frame->psc); + + if (_NSIG_WORDS > 1) + copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + + setup_sigcontext(&context, regs, set->sig[0]); + if (copy_to_user (&frame->sc, &context, sizeof(context))) + goto segv_and_exit; + + /* Set up to return from userspace. */ + __put_user(frame->retcode, &frame->pretcode); + /* addaw #20,sp */ + __put_user(0xdefc0014, (long *)(frame->retcode + 0)); + /* moveq #,d0; trap #0 */ + __put_user(0x70004e40 + (__NR_sigreturn << 16), + (long *)(frame->retcode + 4)); - /* return address points to code on stack */ + push_cache ((unsigned long) &frame->retcode); - if(put_user((ulong)(frame+4), tframe)) - do_exit(SIGSEGV); - tframe++; - if (current->exec_domain && current->exec_domain->signal_invmap) - __put_user(current->exec_domain->signal_invmap[signr], tframe); - else - __put_user(signr, tframe); - tframe++; + /* + * no matter what frame format we were using before, we + * will do the "RTE" using a normal 4 word frame. + */ + regs->format = 0; - __put_user(regs->vector, tframe); tframe++; - /* "scp" parameter. points to sigcontext */ - __put_user((ulong)(frame+6), tframe); tframe++; - -/* set up the return code... */ - __put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */ - __put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */ - -/* Flush caches so the instructions will be correctly executed. (MA) */ - cache_push_v ((unsigned long)frame, (int)tframe - (int)frame); - -/* setup and copy the sigcontext structure */ - context.sc_mask = oldmask; - context.sc_usp = rdusp(); - context.sc_d0 = regs->d0; - context.sc_d1 = regs->d1; - context.sc_a0 = regs->a0; - context.sc_a1 = regs->a1; - context.sc_sr = regs->sr; - context.sc_pc = regs->pc; - context.sc_formatvec = (regs->format << 12 | regs->vector); - __asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory"); - if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){ - fpu_version = context.sc_fpstate[0]; - __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t" - "fmoveml %/fpcr/%/fpsr/%/fpiar,%1" - : /* no outputs */ - : "m" (*context.sc_fpregs), - "m" (*context.sc_fpcntl) - : "memory"); + /* Set up registers for signal handler */ + wrusp ((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#if DEBUG + printk("Performing stackadjust=%04x\n", regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = regs->vector; + tregs->format = regs->format; + tregs->pc = regs->pc; + tregs->sr = regs->sr; } - if (copy_to_user (tframe, &context, sizeof(context))) - do_exit(SIGSEGV); + return; + +segv_and_exit: + do_exit(SIGSEGV); +} + +static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int fsize = frame_extra_sizes[regs->format]; + + if (fsize < 0) { +#ifdef DEBUG + printk ("setup_frame: Unknown frame format %#x\n", + regs->format); +#endif + goto segv_and_exit; + } + + frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8); + + /* XXX: Check here if we need to switch stacks.. */ + + if (fsize) { + if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize)) + goto segv_and_exit; + regs->stkadj = fsize; + } + + __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + __put_user(&frame->info, &frame->pinfo); + __put_user(&frame->uc, &frame->puc); + __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Clear all the bits of the ucontext we don't use. */ + clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + rt_setup_ucontext(&frame->uc, regs); + if (copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set))) + goto segv_and_exit; + + /* Set up to return from userspace. */ + __put_user(frame->retcode, &frame->pretcode); + /* movel #,d0; trap #0 */ + __put_user(0x203c, (short *)(frame->retcode + 0)); + __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2)); + __put_user(0x4e40, (short *)(frame->retcode + 6)); + + push_cache ((unsigned long) &frame->retcode); /* * no matter what frame format we were using before, we @@ -345,7 +853,7 @@ /* Set up registers for signal handler */ wrusp ((unsigned long) frame); - regs->pc = (unsigned long) sa->sa_handler; + regs->pc = (unsigned long) ka->sa.sa_handler; /* Prepare to skip over the extra stuff in the exception frame. */ if (regs->stkadj) { @@ -361,13 +869,18 @@ tregs->pc = regs->pc; tregs->sr = regs->sr; } + return; + +segv_and_exit: + do_exit(SIGSEGV); } /* * OK, we're invoking a handler */ -static inline void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs) +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) { /* are we from a system call? */ if (regs->orig_d0 >= 0) { @@ -378,7 +891,7 @@ break; case -ERESTARTSYS: - if (!(sa->sa_flags & SA_RESTART)) { + if (!(ka->sa.sa_flags & SA_RESTART)) { regs->d0 = -EINTR; break; } @@ -390,12 +903,19 @@ } /* set up the stack frame */ - setup_frame(sa, regs, signr, oldmask); + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = NULL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + } } /* @@ -407,29 +927,28 @@ * that the kernel can handle, and then we build all the user-level signal * handling stack-frames in one go after that. */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) { - unsigned long mask = ~current->blocked; - unsigned long signr; - struct sigaction * sa; + siginfo_t info; + struct k_sigaction *ka; current->tss.esp0 = (unsigned long) regs; - /* If the process is traced, all signals are passed to the debugger. */ - if (current->flags & PF_PTRACED) - mask = ~0UL; - while ((signr = current->signal & mask)) { - __asm__("bfffo %2,#0,#0,%1\n\t" - "bfclr %0,%1,#1\n\t" - "eorw #31,%1" - :"=m" (current->signal),"=d" (signr) - :"0" (current->signal), "1" (signr)); - sa = current->sig->action + signr; - signr++; + if (!oldset) + oldset = ¤t->blocked; + + for (;;) { + int signr; + + signr = dequeue_signal(¤t->blocked, &info); + + if (!signr) + break; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; + regs->sr &= ~PS_T; /* Did we come from a system call? */ if (regs->orig_d0 >= 0) { @@ -443,11 +962,12 @@ } notify_parent(current, SIGCHLD); schedule(); + + /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) { discard_frame: - /* Make sure that a faulted bus cycle - isn't restarted (only needed on the - 68030). */ + /* Make sure that a faulted bus cycle isn't + restarted (only needed on the 680[23]0). */ if (regs->format == 10 || regs->format == 11) { regs->stkadj = frame_extra_sizes[regs->format]; regs->format = 0; @@ -455,26 +975,43 @@ continue; } current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) goto discard_frame; - if (_S(signr) & current->blocked) { - current->signal |= _S(signr); - mask &= ~_S(signr); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if (sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; - /* check for SIGCHLD: it's special */ - while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } - if (sa->sa_handler == SIG_DFL) { + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + if (current->pid == 1) continue; + switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; @@ -482,31 +1019,35 @@ case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; + /* FALLTHRU */ + case SIGSTOP: - if (current->flags & PF_PTRACED) - continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & - SA_NOCLDSTOP)) + if (!(current->p_pptr->sig->action[SIGCHLD-1] + .sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: - if (current->binfmt && current->binfmt->core_dump) { - if (current->binfmt->core_dump(signr, regs)) - signr |= 0x80; - } - /* fall through */ + if (current->binfmt + && current->binfmt->core_dump + && current->binfmt->core_dump(signr, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + default: - current->signal |= _S(signr & 0x7f); + sigaddset(¤t->signal, signr); current->flags |= PF_SIGNALED; - do_exit(signr); + do_exit(exit_code); + /* NOTREACHED */ } } - handle_signal(signr, sa, oldmask, regs); + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); return 1; } diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c --- v2.1.86/linux/arch/m68k/kernel/sys_m68k.c Thu Jul 31 13:09:16 1997 +++ linux/arch/m68k/kernel/sys_m68k.c Thu Feb 12 16:30:12 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -308,6 +309,10 @@ } if (!--i && len) { + /* + * No need to page align here since it is done by + * virt_to_phys_040(). + */ addr += PAGE_SIZE; i = PAGE_SIZE / 16; /* Recompute physical address when crossing a page @@ -462,7 +467,14 @@ } if (!--i && len) { + + /* + * We just want to jump to the first cache line + * in the next page. + */ addr += PAGE_SIZE; + addr &= PAGE_MASK; + i = PAGE_SIZE / 16; /* Recompute physical address when crossing a page boundary. */ @@ -559,13 +571,13 @@ cacr |= 4; if (cache & FLUSH_CACHE_DATA) cacr |= 0x400; - len >>= 4; + len >>= 2; while (len--) { __asm__ __volatile__ ("movec %1, %%caar\n\t" "movec %0, %%cacr" : /* no outputs */ : "r" (cacr), "r" (addr)); - addr += 16; + addr += 4; } } else { /* Flush the whole cache, even if page granularity requested. */ @@ -587,4 +599,14 @@ out: unlock_kernel(); return ret; +} + +/* + * Old cruft + */ +asmlinkage int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; } diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c --- v2.1.86/linux/arch/m68k/kernel/time.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/kernel/time.c Thu Feb 12 16:30:12 1998 @@ -66,11 +66,35 @@ */ if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) + xtime.tv_usec < 500000 + (tick >> 1)) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672< #include #include +#include #ifdef CONFIG_KGDB #include #endif @@ -64,23 +65,10 @@ __ALIGN_STR "\n" SYMBOL_NAME_STR(nmihandler) ": rte"); -__initfunc(void trap_init (void)) +__initfunc(void base_trap_init(void)) { - int i; - /* setup the exception vector table */ - __asm__ volatile ("movec %0,%/vbr" : : "r" ((void*)vectors)); - - for (i = 48; i < 64; i++) - vectors[i] = trap; - - for (i = 64; i < 256; i++) - vectors[i] = inthandler; - - /* if running on an amiga, make the NMI interrupt do nothing */ - if (MACH_IS_AMIGA) { - vectors[VEC_INT7] = nmihandler; - } + __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); if (CPU_IS_040) { /* set up FPSP entry points */ @@ -134,6 +122,23 @@ } } +__initfunc(void trap_init (void)) +{ + int i; + + for (i = 48; i < 64; i++) + if (!vectors[i]) + vectors[i] = trap; + + for (i = 64; i < 256; i++) + vectors[i] = inthandler; + + /* if running on an amiga, make the NMI interrupt do nothing */ + if (MACH_IS_AMIGA) { + vectors[VEC_INT7] = nmihandler; + } +} + void set_evector(int vecnum, void (*handler)(void)) { if (vecnum >= 0 && vecnum <= 256) @@ -202,7 +207,7 @@ return; } - if (fslw & (MMU060_DESC_ERR | MMU060_WP)) { + if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { unsigned long errorcode; unsigned long addr = fp->un.fmt4.effaddr; errorcode = ((fslw & MMU060_WP) ? 1 : 0) | @@ -230,9 +235,9 @@ static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr) { unsigned long mmusr; - unsigned long fs = get_fs(); + mm_segment_t fs = get_fs(); - set_fs (fc); + set_fs (MAKE_MM_SEG(fc)); if (iswrite) /* write */ @@ -261,7 +266,7 @@ unsigned long wbd, struct frame *fp) { - unsigned long fs = get_fs (); + mm_segment_t fs = get_fs (); unsigned long mmusr; unsigned long errorcode; @@ -277,7 +282,7 @@ /* just return if we can't perform the writeback */ return; - set_fs (wbs & WBTM_040); + set_fs (MAKE_MM_SEG(wbs & WBTM_040)); switch (wbs & WBSIZ_040) { case BA_SIZE_BYTE: put_user (wbd & 0xff, (char *)wba); @@ -833,34 +838,37 @@ asmlinkage void trap_c(struct frame *fp) { int sig; + siginfo_t info; - if ((fp->ptregs.sr & PS_S) - && ((fp->ptregs.vector) >> 2) == VEC_TRACE - && !(fp->ptregs.sr & PS_T)) { - /* traced a trapping instruction */ - unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4; - current->flags |= PF_DTRACE; - /* clear the trace bit */ - (*(unsigned short *)lp) &= ~PS_T; - return; - } else if (fp->ptregs.sr & PS_S) { - bad_super_trap(fp); + if (fp->ptregs.sr & PS_S) { + if ((fp->ptregs.vector >> 2) == VEC_TRACE) { + /* traced a trapping instruction */ + current->flags |= PF_DTRACE; + } else + bad_super_trap(fp); return; } /* send the appropriate signal to the user program */ switch ((fp->ptregs.vector) >> 2) { case VEC_ADDRERR: + info.si_code = BUS_ADRALN; sig = SIGBUS; break; - case VEC_BUSERR: - sig = SIGSEGV; - break; case VEC_ILLEGAL: - case VEC_PRIV: case VEC_LINE10: case VEC_LINE11: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + case VEC_PRIV: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + break; case VEC_COPROC: + info.si_code = ILL_COPROC; + sig = SIGILL; + break; case VEC_TRAP1: case VEC_TRAP2: case VEC_TRAP3: @@ -875,51 +883,76 @@ case VEC_TRAP12: case VEC_TRAP13: case VEC_TRAP14: + info.si_code = ILL_ILLTRP; sig = SIGILL; break; case VEC_FPBRUC: + case VEC_FPOE: + case VEC_FPNAN: + info.si_code = FPE_FLTINV; + sig = SIGFPE; + break; case VEC_FPIR: + info.si_code = FPE_FLTRES; + sig = SIGFPE; + break; case VEC_FPDIVZ: + info.si_code = FPE_FLTDIV; + sig = SIGFPE; + break; case VEC_FPUNDER: - case VEC_FPOE: + info.si_code = FPE_FLTUND; + sig = SIGFPE; + break; case VEC_FPOVER: - case VEC_FPNAN: - { - unsigned char fstate[FPSTATESIZE]; - - __asm__ __volatile__ (".chip 68k/68881\n\t" - "fsave %0@\n\t" - ".chip 68k" : : "a" (fstate) : "memory"); - /* Set the exception pending bit in the 68882 idle frame */ - if (*(unsigned short *) fstate == 0x1f38) - { - fstate[fstate[1]] |= 1 << 3; - __asm__ __volatile__ (".chip 68k/68881\n\t" - "frestore %0@\n\t" - ".chip 68k" : : "a" (fstate)); - } - } - /* fall through */ + info.si_code = FPE_FLTOVF; + sig = SIGFPE; + break; case VEC_ZERODIV: + info.si_code = FPE_INTDIV; + sig = SIGFPE; + break; + case VEC_CHK: case VEC_TRAP: + info.si_code = FPE_INTOVF; sig = SIGFPE; break; case VEC_TRACE: /* ptrace single step */ - fp->ptregs.sr &= ~PS_T; + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; case VEC_TRAP15: /* breakpoint */ + info.si_code = TRAP_BRKPT; sig = SIGTRAP; break; default: + info.si_code = ILL_ILLOPC; sig = SIGILL; break; } - - send_sig (sig, current, 1); -} - -asmlinkage void set_esp0 (unsigned long ssp) -{ - current->tss.esp0 = ssp; + info.si_signo = sig; + info.si_errno = 0; + switch (fp->ptregs.format) { + default: + info.si_addr = (void *) fp->ptregs.pc; + break; + case 2: + info.si_addr = (void *) fp->un.fmt2.iaddr; + break; + case 7: + info.si_addr = (void *) fp->un.fmt7.effaddr; + break; + case 9: + info.si_addr = (void *) fp->un.fmt9.iaddr; + break; + case 10: + info.si_addr = (void *) fp->un.fmta.daddr; + break; + case 11: + info.si_addr = (void *) fp->un.fmtb.daddr; + break; + } + force_sig_info (sig, &info, current); } void die_if_kernel (char *str, struct pt_regs *fp, int nr) diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile --- v2.1.86/linux/arch/m68k/mac/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/Makefile Thu Feb 12 16:30:13 1998 @@ -0,0 +1,16 @@ +# +# Makefile for Linux arch/m68k/mac 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... + +EXTRA_CFLAGS := -Wa,-m68020 + +O_TARGET := mac.o +O_OBJS := config.o ksyms.o bootparse.o macints.o via6522.o \ + mackeyb.o adb-bus.o macboing.o debug.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c --- v2.1.86/linux/arch/m68k/mac/adb-bus.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/adb-bus.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,2134 @@ +/* + * MACII ADB keyboard handler. + * Copyright (c) 1997 Alan Cox + * + * Derived from code + * Copyright (C) 1996 Paul Mackerras. + * + * MSch (9/97) Partial rewrite of interrupt handler to MacII style + * ADB handshake, based on: + * - Guide to Mac Hardware + * - Guido Koerber's session with a logic analyzer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "via6522.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MACII /* For now - will be a switch */ + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ + +/* Bits in B data register: ADB transaction states MacII */ +#define ST_MASK 0x30 /* mask for selecting ADB state bits */ +/* ADB transaction states according to GMHW */ +#define ST_CMD 0x00 /* ADB state: command byte */ +#define ST_EVEN 0x10 /* ADB state: even data byte */ +#define ST_ODD 0x20 /* ADB state: odd data byte */ +#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#ifdef USE_ORIG +#define SR_EXT 0x1c /* Shift on external clock */ +#else +#define SR_EXT 0x0c /* Shift on external clock */ +#endif +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define SR_DATA 0x08 /* Shift register data */ +#define SR_CLOCK 0x10 /* Shift register clock */ + +static struct adb_handler { + void (*handler)(unsigned char *, int, struct pt_regs *); +} adb_handler[16]; + +static enum adb_state { + idle, + sent_first_byte, + sending, + reading, + read_done, + awaiting_reply +} adb_state; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static unsigned char cuda_rbuf[16]; +static unsigned char *reply_ptr; +static int reply_len; +static int reading_reply; +static int data_index; +static int first_byte; +static int prefix_len; + +static int status = ST_IDLE|TREQ; +static int last_status; +/*static int adb_delay;*/ +int in_keybinit = 1; + +static void adb_start(void); +extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs); +extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs); +extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs); +extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); + +/* + * Misc. defines for testing + */ + +extern int console_loglevel; + +#define ADBDEBUG_STATUS (1) +#define ADBDEBUG_STATE (2) +#define ADBDEBUG_READ (4) +#define ADBDEBUG_WRITE (8) +#define ADBDEBUG_START (16) +#define ADBDEBUG_RETRY (32) +#define ADBDEBUG_POLL (64) +#define ADBDEBUG_INT (128) +#define ADBDEBUG_PROT (256) +#define ADBDEBUG_SRQ (512) +#define ADBDEBUG_REQUEST (1024) +#define ADBDEBUG_INPUT (2048) +#define ADBDEBUG_DEVICE (4096) + + +#define DEBUG_ADB + +#ifdef DEBUG_ADB +#define ADBDEBUG (ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST) +#else +#define ADBDEBUG (0) +#endif + +#define TRY_CUDA + +void adb_bus_init(void) +{ + unsigned long flags; + unsigned char c; + + save_flags(flags); + cli(); + + /* + * Setup ADB + */ + + switch(macintosh_config->adb_type) + { + + case MAC_ADB_II: + printk("adb: MacII style keyboard/mouse driver.\n"); + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); + /* + * Docs suggest TREQ should be output - that seems nuts + * BSD agrees here :-) + * Setup vPCR ?? + */ + +#ifdef USE_ORIG + /* Lower the bus signals (MacII is active low it seems ???) */ + via_write(via1, vBufB, via_read(via1, vBufB)&~TACK); +#else + /* Corresponding state: idle (clear state bits) */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); + last_status = (via_read(via1, vBufB)&~ST_MASK); +#endif + /* Shift register on input */ + c=via_read(via1, vACR); + c&=~SR_CTRL; /* Clear shift register bits */ + c|=SR_EXT; /* Shift on external clock; out or in? */ + via_write(via1, vACR, c); + /* Wipe any pending data and int */ + via_read(via1, vSR); + + /* This is interrupts on enable SR for keyboard */ + via_write(via1, vIER, IER_SET|SR_INT); + /* This clears the interrupt bit */ + via_write(via1, vIFR, SR_INT); +#if 0 + ct=1000; + while( ct-- && (via_read(via1, vBufB)&TREQ)) + udelay(1000); + if(ct<0) + printk("No sync occured\n"); + ct=1000; + while( ct-- && !(via_read(via1, vIFR)&SR_INT)) + udelay(1000); + if(ct<0) + printk("No sync 2 occured\n"); + via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)|TACK); + while( ct-- && !(via_read(via1, vBufB)&TREQ)) + udelay(1000); + if(ct<0) + printk("No sync 3 occured\n"); + ct=1000; + while( ct-- && !(via_read(via1, vIFR)&SR_INT)) + udelay(1000); + if(ct<0) + printk("No sync 4 occured\n"); + via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)|TIP); +#endif + /* + * Ok we probably ;) have a ready to use adb bus. Its also + * hopefully idle (Im assuming the mac didnt leave a half + * complete transaction on booting us). + */ + + request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, + "adb interrupt", adb_interrupt); + adb_state = idle; + break; + /* + * Unsupported; but later code doesn't notice !! + */ + case MAC_ADB_CUDA: + printk("adb: CUDA interface.\n"); +#ifdef TRY_CUDA + /* don't know what to set up here ... */ + adb_state = idle; + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); + request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, + "adb CUDA interrupt", adb_cuda_interrupt); + break; +#else + goto nosupp; +#endif + case MAC_ADB_IISI: + printk("adb: Using IIsi hardware.\n"); + goto nosupp; + default: + printk("adb: Unknown hardware interface.\n"); + nosupp: + printk("adb: Interface unsupported.\n"); + restore_flags(flags); + return; + } + + /* + * XXX: interrupt only registered if supported HW !! + * -> unsupported HW will just time out on keyb_init! + */ +#if 0 + request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, + "adb interrupt", adb_interrupt); +#endif +#ifdef DEBUG_ADB_INTS + request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, + "adb clock interrupt", adb_clock_interrupt); + request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK, + "adb data interrupt", adb_data_interrupt); +#endif + + printk("adb: init done.\n"); + restore_flags(flags); +} + +#define WAIT_FOR(cond, what) \ + do { \ + for (x = 1000; !(cond); --x) { \ + if (x == 0) { \ + printk("Timeout waiting for " what); \ + return 0; \ + } \ + __delay(100*160); \ + } \ + } while (0) + +/* + * Construct and send an adb request + * This function is the main entry point into the ADB driver from + * kernel code; it takes the request data supplied and populates the + * adb_request structure. + * In order to keep this interface independent from any assumption about + * the underlying ADB hardware, we take requests in CUDA format here, + * the ADB packet 'prefixed' with a packet type code. + * Non-CUDA hardware is confused by this, so we strip the packet type + * here depending on hardware type ... + */ +int adb_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i, start; + + va_start(list, nbytes); + + /* + * skip first byte if not CUDA + */ + if (macintosh_config->adb_type != MAC_ADB_CUDA) { + start = va_arg(list, int); + nbytes--; + } + req->nbytes = nbytes; + req->done = done; +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("adb_request, data bytes: "); +#endif + for (i = 0; i < nbytes; ++i) { + req->data[i] = va_arg(list, int); +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("%x ", req->data[i]); +#endif + } +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk(" !\n"); +#endif + va_end(list); + /* + * XXX: This might be fatal if no reply is generated (i.e. Listen) ! + * Currently, the interrupt handler 'fakes' a reply on non-TALK + * commands for this reason. + * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA + * Macs, and some mechanism to remember the last issued TALK + * request for resending it repeatedly on timeout! + */ + req->reply_expected = 1; + return adb_send_request(req); +} + +/* + * Construct an adb request for later sending + * This function only populates the adb_request structure, without + * actually queueing it. + * Reason: Poll requests and Talk requests need to be handled in a way + * different from 'user' requests; no reply_expected is set and + * Poll requests need to be placed at the head of the request queue. + * Using adb_request results in implicit queueing at the tail of the + * request queue (duplicating the Poll) with reply_expected set. + * No adjustment of packet data is necessary, as this mechanisnm is not + * used by CUDA hardware (Autopoll used instead). + */ +int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i; + + req->nbytes = nbytes; + req->done = done; + va_start(list, nbytes); +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("adb__build_request, data bytes: "); +#endif + /* + * skip first byte if not CUDA ? + */ + for (i = 0; i < nbytes; ++i) { + req->data[i] = va_arg(list, int); +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("%x ", req->data[i]); +#endif + } +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk(" !\n"); +#endif + va_end(list); + + req->reply_expected = 0; + return 0; +} + +/* + * Send an ADB poll (Talk, tagged on the front of the request queue) + */ +void adb_queue_poll(void) +{ + static int pod=0; + static int in_poll=0; + static struct adb_request r; + unsigned long flags; + + if(in_poll) + printk("Double poll!\n"); + + in_poll++; + pod++; + if(pod>7) /* 15 */ + pod=0; + +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("adb: Polling %d\n",pod); +#endif + + /* XXX: that's a TALK, register 0, MacII version */ + adb_build_request(&r,NULL, 1, (pod<<4|0xC)); + + r.reply_expected=0; + r.done=NULL; + r.sent=0; + r.got_reply=0; + r.reply_len=0; + save_flags(flags); + cli(); + /* Poll inserted at head of queue ... */ + r.next=current_req; + current_req=&r; + restore_flags(flags); + adb_start(); + in_poll--; +} + +/* + * Send an ADB retransmit (Talk, appended to the request queue) + */ +void adb_retransmit(int device) +{ + static int in_retransmit=0; + static struct adb_request rt; + unsigned long flags; + + if(in_retransmit) + printk("Double retransmit!\n"); + + in_retransmit++; + +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("adb: Sending retransmit: %d\n", device); +#endif + + /* MacII version */ + adb_build_request(&rt,NULL, 1, (device<<4|0xC)); + + rt.reply_expected = 0; + rt.done = NULL; + rt.sent = 0; + rt.got_reply = 0; + rt.reply_len = 0; + rt.next = NULL; + + save_flags(flags); + cli(); + + /* Retransmit inserted at tail of queue ... */ + + if (current_req != NULL) + { + last_req->next = &rt; + last_req = &rt; + } + else + { + current_req = &rt; + last_req = &rt; + } + + /* always restart driver (send_retransmit used in place of adb_start!)*/ + + if (adb_state == idle) + adb_start(); + + restore_flags(flags); + in_retransmit--; +} + +/* + * Queue an ADB request; start ADB transfer if necessary + */ +int adb_send_request(struct adb_request *req) +{ + unsigned long flags; + + req->next = 0; + req->sent = 0; + req->got_reply = 0; + req->reply_len = 0; + save_flags(flags); + cli(); + + if (current_req != NULL) + { + last_req->next = req; + last_req = req; + } + else + { + current_req = req; + last_req = req; + if (adb_state == idle) + adb_start(); + } + + restore_flags(flags); + return 0; +} + +static int nclock, ndata; + +static int need_poll = 0; +static int command_byte = 0; +static int last_reply = 0; +static int last_active = 0; + +static struct adb_request *retry_req; + +/* + * Start sending ADB packet + */ +static void adb_start(void) +{ + unsigned long flags; + struct adb_request *req; + + /* + * We get here on three 'sane' conditions: + * 1) called from send_adb_request, if adb_state == idle + * 2) called from within adb_interrupt, if adb_state == idle + * (after receiving, or after sending a LISTEN) + * 3) called from within adb_interrupt, if adb_state == sending + * and no reply is expected (immediate next command). + * Maybe we get here on SRQ as well ?? + */ + + /* get the packet to send */ + req = current_req; + /* assert adb_state == idle */ + if (adb_state != idle) { + printk("ADB: adb_start called while driver busy (%p %x %x)!\n", + req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); + return; + } + if (req == 0) + return; + save_flags(flags); + cli(); + +#if (ADBDEBUG & ADBDEBUG_START) + if (console_loglevel == 10) + printk("adb_start: request %p ", req); +#endif + + nclock = 0; + ndata = 0; + + /* + * IRQ signaled ?? (means ADB controller wants to send, or might + * be end of packet if we were reading) + */ + if ((via_read(via1, vBufB)& TREQ) == 0) + { + switch(macintosh_config->adb_type) + { + /* + * FIXME - we need to restart this on a timer + * or a collision at boot hangs us. + * Never set adb_state to idle here, or adb_start + * won't be called again from send_request! + * (need to re-check other cases ...) + */ + case MAC_ADB_CUDA: + /* printk("device busy - fail\n"); */ + restore_flags(flags); + /* a byte is coming in from the CUDA */ + return; + case MAC_ADB_II: + /* + * if the interrupt handler set the need_poll + * flag, it's hopefully a SRQ poll or re-Talk + * so we try to send here anyway + */ + if (!need_poll) { + printk("device busy - retry %p state %d status %x!\n", + req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); + retry_req = req; + /* set ADB status here ? */ + restore_flags(flags); + return; + } else { +#if (ADBDEBUG & ADBDEBUG_START) + if (console_loglevel == 10) + printk("device busy - polling; state %d status %x!\n", + adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); +#endif + need_poll = 0; + break; + } + } + } + +#if 0 + /* + * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here! + * OTOH: setting ST_CMD in the interrupt routine would make the + * ADB contoller shift in before this routine starts shifting out ... + */ + if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE) + { +#if (ADBDEBUG & ADBDEBUG_STATE) + if (console_loglevel == 10) + printk("ADB bus not idle (%x), retry later!\n", + via_read(via1, vBufB)&(ST_MASK|TREQ)); +#endif + retry_req = req; + restore_flags(flags); + return; + } +#endif + + /* + * Another retry pending? (sanity check) + */ + if (retry_req) { +#if (ADBDEBUG & ADBDEBUG_RETRY) + if (console_loglevel == 10) + if (retry_req == req) + /* new requests are appended at tail of request queue */ + printk("adb_start: retry %p pending ! \n", req); + else + /* poll requests are added to the head of queue */ + printk("adb_start: retry %p pending, req %p (poll?) current! \n", + retry_req, req); +#endif + retry_req = NULL; + } + + /* + * Seems OK, go for it! + */ + switch(macintosh_config->adb_type) + { + case MAC_ADB_CUDA: + /* store command byte (first byte is 'type' byte) */ + command_byte = req->data[1]; + /* set the shift register to shift out and send a byte */ + via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + via_write(via1, vSR, req->data[0]); + via_write(via1, vBufB, via_read(via1, vBufB)&~TIP); + break; + case MAC_ADB_II: + /* store command byte */ + command_byte = req->data[0]; + /* Output mode */ + via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + /* Load data */ + via_write(via1, vSR, req->data[0]); +#ifdef USE_ORIG + /* Turn off TIP/TACK - this should tell the external logic to + start the external shift clock */ +/* via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/ + via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK)); +#else + /* set ADB state to 'command' */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD); +#endif + break; + } +#if (ADBDEBUG & ADBDEBUG_START) + if (console_loglevel == 10) + printk("sent first byte of %d: %x, (%x %x) ... ", + req->nbytes, req->data[0], adb_state, + (via_read(via1, vBufB) & (ST_MASK|TREQ)) ); +#endif + adb_state = sent_first_byte; + data_index = 1; + restore_flags(flags); +} + +/* + * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs) + */ +void adb_poll(void) +{ + unsigned char c; + unsigned long flags; + save_flags(flags); + cli(); + c=via_read(via1, vIFR); +#if (ADBDEBUG & ADBDEBUG_POLL) +#ifdef DEBUG_ADB_INTS + if (console_loglevel == 10) { + printk("adb_poll: IFR %x state %x cl %d dat %d ", + c, adb_state, nclock, ndata); + if (c & (SR_CLOCK|SR_DATA)) { + if (c & SR_CLOCK) + printk("adb clock event "); + if (c & SR_DATA) + printk("adb data event "); + } + } +#else + if (console_loglevel == 10) + printk("adb_poll: IFR %x state %x ", + c, adb_state); +#endif + if (console_loglevel == 10) + printk("\r"); +#endif + if (c & SR_INT) + { +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("adb_poll: adb interrupt event\n"); +#endif + adb_interrupt(0, 0, 0); + } + restore_flags(flags); +} + +/* + * Debugging gimmicks + */ +void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + nclock++; +} + +void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + ndata++; +} + +/* + * The notorious ADB interrupt handler - does all of the protocol handling, + * except for starting new send operations. Relies heavily on the ADB + * controller sending and receiving data, thereby generating SR interrupts + * for us. This means there has to be always activity on the ADB bus, otherwise + * the whole process dies and has to be re-kicked by sending TALK requests ... + * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type + * ADB the problem isn't solved yet (retransmit of the latest active TALK seems + * a good choice; either on timeout or on a timer interrupt). + * + * The basic ADB state machine was left unchanged from the original MacII code + * by Alan Cox, which was based on the CUDA driver for PowerMac. + * The syntax of the ADB status lines seems to be totally different on MacII, + * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for + * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start + * and end of a receive packet are signaled by asserting /IRQ on the interrupt + * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on + * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the + * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB + * protocol with a logic analyzer!!) + * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK + * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for + * receiving. No clue how timeouts are handled; SRQ seems to be sent as a + * separate packet. Quite a few changes have been made outside the handshake + * code, so I don't know if the CUDA code still behaves as before. + * + * Note: As of 21/10/97, the MacII ADB part works including timeout detection + * and retransmit (Talk to the last active device). Cleanup of code and + * testing of the CUDA functionality is required, though. + * Note2: As of 13/12/97, CUDA support is definitely broken ... + * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG + * conditionals can be a start?) + */ +void adb_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int x, adbdir; + struct adb_request *req; + + last_status = status; + +#ifdef USE_ORIG + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); +#else + if (macintosh_config->adb_type==MAC_ADB_CUDA) + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); + else + /* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */ + status = (via_read(via1, vBufB) & (ST_MASK|TREQ)); +#endif + adbdir = (via_read(via1, vACR) & SR_OUT); +#if (ADBDEBUG & ADBDEBUG_INT) + if (console_loglevel == 10) + printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n", + adb_state, status, last_status, adbdir); +#endif + + + switch (adb_state) + { + case idle: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data - unsolicited */ + if (status != TREQ) + printk("cuda: state=idle, status=%x\n", status); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { +#if (ADBDEBUG & ADBDEBUG_STATUS) + if (status == TREQ && !adbdir) + /* that's: not IRQ, idle, input -> weird */ + printk("adb_macII: idle, status=%x dir=%x\n", + status, adbdir); +#endif + x = via_read(via1, vSR); + first_byte = x; +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk("adb_macII: receiving unsol. packet: %x (%x %x) ", + x, adb_state, status); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); +#else + /* set ADB state = even for first data byte */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); +#endif + } + adb_state = reading; + reply_ptr = cuda_rbuf; + reply_len = 0; + reading_reply = 0; + prefix_len = 0; + if (macintosh_config->adb_type==MAC_ADB_II) { + *reply_ptr++ = ADB_PACKET; + *reply_ptr++ = first_byte; + *reply_ptr++ = command_byte; /*first_byte;*/ + reply_len = 3; + prefix_len = 3; + } + break; + + case awaiting_reply: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data of a reply */ + if (status != TREQ) + printk("cuda: state=awaiting_reply, status=%x\n", status); + x = via_read(via1, vSR); + via_write(via1,vBufB, + via_read(via1, vBufB)&~TIP); + } else if(macintosh_config->adb_type==MAC_ADB_II) { + /* handshake etc. for II ?? */ + x = via_read(via1, vSR); + first_byte = x; +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk("adb_macII: reading reply: %x (%x %x) ", + x, adb_state, status); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); +#else + /* set ADB state = even for first data byte */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); +#endif + } + adb_state = reading; + reply_ptr = current_req->reply; + reading_reply = 1; + reply_len = 0; + prefix_len = 0; + if (macintosh_config->adb_type==MAC_ADB_II) { + *reply_ptr++ = ADB_PACKET; + *reply_ptr++ = first_byte; + *reply_ptr++ = first_byte; /* should be command byte */ + reply_len = 3; + prefix_len = 3; + } + break; + + case sent_first_byte: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TREQ + TIP + SR_OUT) + { + /* collision */ + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TIP|TACK); + adb_state = idle; + } + else + { + /* assert status == TIP + SR_OUT */ + if (status != TIP + SR_OUT) + printk("cuda: state=sent_first_byte status=%x\n", status); + via_write(via1,vSR,current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index = 2; + adb_state = sending; + } + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + /* how to detect a collision here ?? */ +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" sending: %x (%x %x) ", + current_req->data[1], adb_state, status); +#endif + /* maybe we're already done (Talk, or Poll)? */ + if (data_index >= current_req->nbytes) + { + /* assert it's a Talk ?? */ + if ( (command_byte&0xc) != 0xc + && console_loglevel == 10 ) + printk("ADB: single byte command, no Talk: %x!\n", + command_byte); +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" -> end (%d of %d) (%x %x)!\n", + data_index, current_req->nbytes, adb_state, status); +#endif + current_req->sent = 1; + if (current_req->reply_expected) + { +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk("ADB: reply expected on poll!\n"); +#endif + adb_state = awaiting_reply; + reading_reply = 0; + } else { +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk("ADB: no reply for poll, not calling done()!\n"); +#endif + req = current_req; + current_req = req->next; +#if 0 /* XXX Not sure about that one ... probably better enabled */ + if (req->done) + (*req->done)(req); +#endif + adb_state = idle; + reading_reply = 0; + } + /* set to shift in */ + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else + /* set ADB state idle - might get SRQ */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif + break; + } +#if (ADBDEBUG & ADBDEBUG_STATUS) + if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT)) + printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n", + status, adbdir); +#endif + /* SR already set to shift out; send byte */ + via_write(via1, vSR, current_req->data[1]); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#else + /* set state to ST_EVEN (first byte was: ST_CMD) */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); +#endif + data_index=2; + adb_state = sending; + } + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) + { + /* end of packet */ + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TACK|TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + /* + * XXX Not sure: maybe only switch to + * input mode on Talk ?? + */ +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" -> end (%d of %d) (%x %x)!\n", + data_index-1, req->nbytes, adb_state, status); +#endif + /* set to shift in */ + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else + /* set ADB state idle - might get SRQ */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif + } + req->sent = 1; + if (req->reply_expected) + { + /* + * maybe fake a reply here on Listen ?? + * Otherwise, a Listen hangs on success + */ + if ( ((req->data[0]&0xc) == 0xc) ) + adb_state = awaiting_reply; + else { + /* + * Reply expected, but none + * possible -> fake reply. + * Problem: sending next command + * should probably be done + * without setting bus to 'idle'! + * (except if no more commands) + */ +#if (ADBDEBUG & ADBDEBUG_PROT) + printk("ADB: reply expected on Listen, faking reply\n"); +#endif + /* make it look weird */ + /* XXX: return reply_len -1? */ + /* XXX: fake ADB header? */ + req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; + req->reply_len = 3; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + /* + * ready with this one, run + * next command or repeat last + * Talk (=idle on II) + */ + /* set state to idle !! */ + adb_state = idle; + if (current_req || retry_req) + adb_start(); + } + } + else + { + current_req = req->next; + if (req->done) + (*req->done)(req); + /* not sure about this */ + /* + * MS: Must set idle, no new request + * started else ! + */ + adb_state = idle; + /* + * requires setting ADB state to idle, + * maybe read a byte ! (done above) + */ + if (current_req || retry_req) + adb_start(); + } + } + else + { + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" %x (%x %x) ", + req->data[data_index], adb_state, status); +#endif + via_write(via1, vSR, req->data[data_index++]); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#else + /* invert state bits, toggle ODD/EVEN */ + x = via_read(via1, vBufB); + via_write(via1, vBufB, + (x&~ST_MASK)|~(x&ST_MASK)); +#endif + } + } + break; + + case reading: +#ifdef POLL_ON_TIMEOUT + if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) +#else + if( (first_byte == 0xFF && (reply_len-prefix_len)==2 + && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || + ((reply_len-prefix_len)==3 + && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) +#endif + { + /* + * possible timeout (in fact, most probably a + * timeout, since SRQ can't be signaled without + * transfer on the bus). + * The last three bytes seen were FF, together + * with the starting byte (in case we started + * on 'idle' or 'awaiting_reply') this probably + * makes four. So this is mostl likely #5! + * The timeout signal is a pattern 1 0 1 0 0.. + * on /INT, meaning we missed it :-( + */ + x = via_read(via1, vSR); + if (x != 0xFF) + printk("ADB: mistaken timeout/SRQ!\n"); + + /* + * ADB status bits: either even or odd. + * adb_state: need to set 'idle' here. + * Maybe saner: set 'need_poll' or + * 'need_resend' here, fall through to + * read_done ?? + */ +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk(" -> read aborted: %x (%x %x)!\n", + x, adb_state, status); +#endif + +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else +#if 0 /* XXX leave status unchanged!! - need to check this again! */ + /* set ADB state to idle (required by adb_start()) */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif +#endif + + /* + * What if the timeout happens on reading a + * reply ?? Assemble error reply and call + * current_request->done()? Keep request + * on queue? + */ + + /* prevent 'busy' in adb_start() */ + need_poll = 1; + + /* + * Timeout: /IRQ alternates high/low during + * 4 'FF' bytes (1 0 1 0 0...) + * We're on byte 5, so we need one + * more backlog here (TBI) .... + */ + if ((status&TREQ) != (last_status&TREQ)) { +#if (ADBDEBUG & ADBDEBUG_SRQ) + if (console_loglevel == 10) + printk("ADB: reply timeout, resending!\n"); +#endif + /* + * first byte received should be the + * command byte timing out !! + */ + if (first_byte != 0xff) + command_byte = first_byte; + + /* + * compute target for retransmit: if + * last_active is set, use that one, + * else use command_byte + */ + if (last_active == -1) + last_active = (command_byte&0xf0)>>4; + adb_state = idle; + /* resend if TALK, don't poll! */ + if (current_req) + adb_start(); + else + /* + * XXX: need to count the timeouts ?? + * restart last active TALK ?? + * If no current_req, reuse old one! + */ + adb_retransmit(last_active); + + } else { + /* + * SRQ: NetBSD suggests /IRQ is asserted!? + */ + if (status&TREQ) + printk("ADB: SRQ signature w/o /INT!\n"); +#if (ADBDEBUG & ADBDEBUG_SRQ) + if (console_loglevel == 10) + printk("ADB: empty SRQ packet!\n"); +#endif + /* Terminate the SRQ packet and poll */ + adb_state = idle; + adb_queue_poll(); + } + /* + * Leave ADB status lines unchanged (means /IRQ + * will still be low when entering adb_start!) + */ + break; + } + if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) + { + /* SRQ tacked on data packet */ + /* Check /IRQ here ?? */ +#if (ADBDEBUG & ADBDEBUG_SRQ) + if (console_loglevel == 10) + printk("\nADB: Packet with SRQ!\n"); +#endif + /* Terminate the packet (SRQ never ends) */ + x = via_read(via1, vSR); + adb_state = read_done; + reply_len -= 3; + reply_ptr -= 3; + need_poll = 1; + /* need to continue; next byte not seen else */ + /* + * XXX: not at all sure here; maybe need to + * send away the reply and poll immediately? + */ + } else { + /* Sanity check */ + if(reply_len>15) + reply_len=0; + /* read byte */ + *reply_ptr = via_read(via1, vSR); + x = *reply_ptr; +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk(" %x (%x %x) ", + *reply_ptr, adb_state, status); +#endif + reply_ptr++; + reply_len++; + } + /* The usual handshake ... */ + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TIP) + { + /* that's all folks */ + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + /* assert status == TIP | TREQ */ + if (status != TIP + TREQ) + printk("cuda: state=reading status=%x\n", status); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + if(macintosh_config->adb_type==MAC_ADB_II) + { + /* + * NetBSD hints that the next to last byte + * is sent with IRQ !! + * Guido found out it's the last one (0x0), + * but IRQ should be asserted already. + * Problem with timeout detection: First + * transition to /IRQ might be second + * byte of timeout packet! + * Timeouts are signaled by 4x FF. + */ + if(!(status&TREQ) && x == 0x00) /* != 0xFF */ + { +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk(" -> read done!\n"); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else +#if 0 /* XXX: we take one more byte (why?), so handshake! */ + /* set ADB state to idle */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#else + /* invert state bits, toggle ODD/EVEN */ + x = via_read(via1, vBufB); + via_write(via1, vBufB, + (x&~ST_MASK)|~(x&ST_MASK)); +#endif +#endif + /* adjust packet length */ + reply_len--; + reply_ptr--; + adb_state = read_done; + } + else + { +#if (ADBDEBUG & ADBDEBUG_STATUS) + if(status!=TIP+TREQ) + printk("macII_adb: state=reading status=%x\n", status); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#else + /* not caught: ST_CMD */ + /* required for re-entry 'reading'! */ + if ((status&ST_MASK) == ST_IDLE) { + /* (in)sanity check - set even */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); + } else { + /* invert state bits, toggle ODD/EVEN */ + x = via_read(via1, vBufB); + via_write(via1, vBufB, + (x&~ST_MASK)|~(x&ST_MASK)); + } +#endif + } + } + break; + + case read_done: + x = via_read(via1, vSR); +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk("ADB: read done: %x (%x %x)!\n", + x, adb_state, status); +#endif + if (reading_reply) + { + req = current_req; + req->reply_len = reply_ptr - req->reply; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + } + else + { + adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); + } + + /* + * remember this device ID; it's the latest we got a + * reply from! + */ + last_reply = command_byte; + last_active = (command_byte&0xf0)>>4; + + + /* + * Assert status = ST_IDLE ?? + */ + /* + * SRQ seen before, initiate poll now + */ + if (need_poll) { +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("ADB: initiate poll!\n"); +#endif + adb_state = idle; + /* + * set ADB status bits?? (unchanged above!) + */ + adb_queue_poll(); + need_poll = 0; + /* hope this is ok; queue_poll runs adb_start */ + break; + } + +#ifdef USE_ORIG + /* + * This will fail - TREQ is active low -> 0 is IRQ !! + */ + if (status == TREQ) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|~TIP); +#else + /* + * /IRQ seen, so the ADB controller has data for us + */ + if (!(status&TREQ)) + { + /* set ADB state to idle */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif + adb_state = reading; + reply_ptr = cuda_rbuf; + reply_len = 0; + prefix_len = 0; + if (macintosh_config->adb_type==MAC_ADB_II) { + *reply_ptr++ = ADB_PACKET; + *reply_ptr++ = command_byte; + reply_len = 2; + prefix_len = 2; + } + reading_reply = 0; + } + else + { + /* + * no IRQ, send next packet or wait + */ + adb_state = idle; + if (current_req) + adb_start(); + else + adb_retransmit(last_active); + } + break; + + default: +#if (ADBDEBUG & ADBDEBUG_STATE) + printk("adb_interrupt: unknown adb_state %d?\n", adb_state); +#endif + } +} + +/* + * Restart of CUDA support: please modify this interrupt handler while + * working at the Quadra etc. ADB driver. We can try to merge them later, or + * remove the CUDA stuff from the MacII handler + */ + +void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int x, status; + struct adb_request *req; + + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); + if (console_loglevel == 10) + printk("adb_interrupt: state=%d status=%x\n", adb_state, status); + + switch (adb_state) + { + case idle: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data - unsolicited */ + if (status != TREQ) + printk("cuda: state=idle, status=%x want=%x\n", + status, TREQ); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + if (status != TREQ) + printk("adb_macII: state=idle status=%x want=%x\n", + status, TREQ); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); + } + adb_state = reading; + reply_ptr = cuda_rbuf; + reply_len = 0; + reading_reply = 0; + break; + + case awaiting_reply: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data of a reply */ + if (status != TREQ) + printk("cuda: state=awaiting_reply, status=%x want=%x\n", + status, TREQ); + x = via_read(via1, vSR); + via_write(via1,vBufB, + via_read(via1, vBufB)&~TIP); + } + adb_state = reading; + reply_ptr = current_req->reply; + reading_reply = 1; + reply_len = 0; + break; + + case sent_first_byte: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TREQ + TIP + SR_OUT) + { + /* collision */ + if (console_loglevel == 10) + printk("cuda: send collision!\n"); + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TIP|TACK); + adb_state = idle; + } + else + { + /* assert status == TIP + SR_OUT */ + if (status != TIP + SR_OUT) + printk("cuda: state=sent_first_byte status=%x want=%x\n", + status, TIP + SR_OUT); + via_write(via1,vSR,current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index = 2; + adb_state = sending; + } + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + if(status!=TIP+SR_OUT) + printk("adb_macII: state=send_first_byte status=%x want=%x\n", + status, TIP+SR_OUT); + via_write(via1, vSR, current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index=2; + adb_state = sending; + } + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) + { + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TACK|TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + } + req->sent = 1; + if (req->reply_expected) + { + adb_state = awaiting_reply; + } + else + { + current_req = req->next; + if (req->done) + (*req->done)(req); + /* not sure about this */ + adb_state = idle; + adb_start(); + } + } + else + { + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + break; + + case reading: + if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) + { + /* Terminate the SRQ packet */ + printk("CUDA: Got an SRQ\n"); + adb_state = idle; + adb_queue_poll(); + break; + } + /* Sanity check - botched in orig. code! */ + if(reply_len>15) { + printk("CUDA: reply buffer overrun!\n"); + /* wrap buffer */ + reply_len=0; + if (reading_reply) + reply_ptr = current_req->reply; + else + reply_ptr = cuda_rbuf; + } + *reply_ptr = via_read(via1, vSR); + if (console_loglevel == 10) + printk(" %p-> %x (%x %x) ", + reply_ptr, *reply_ptr, adb_state, status); + reply_ptr++; + reply_len++; + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TIP) + { + /* that's all folks */ + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + /* assert status == TIP | TREQ */ + if (status != TIP + TREQ) + printk("cuda: state=reading status=%x want=%x\n", + status, TIP + TREQ); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + if(macintosh_config->adb_type==MAC_ADB_II) + { + if( status == TIP) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + if(status!=TIP+TREQ) + printk("macII_adb: state=reading status=%x\n", status); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + break; + + case read_done: + x = via_read(via1, vSR); + if (reading_reply) + { + req = current_req; + req->reply_len = reply_ptr - req->reply; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + } + else + { + adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); + } + + if (status == TREQ) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|~TIP); + adb_state = reading; + reply_ptr = cuda_rbuf; + reading_reply = 0; + } + else + { + adb_state = idle; + adb_start(); + } + break; + + default: + printk("adb_interrupt: unknown adb_state %d?\n", adb_state); + } +} + +/* + * The 'reply delivery' routine; determines which device sent the + * request and calls the appropriate handler. + * Reply data are expected in CUDA format (again, argh...) so we need + * to fake this in the interrupt handler for MacII. + * Only one handler per device ID is currently possible. + * XXX: is the ID field here representing the default or real ID? + */ +static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs) +{ + int i, id; + + switch (buf[0]) + { + case ADB_PACKET: + /* what's in buf[1] ?? */ + id = buf[2] >> 4; +#if 0 + xmon_printf("adb packet: "); + for (i = 0; i < nb; ++i) + xmon_printf(" %x", buf[i]); + xmon_printf(", id = %d\n", id); +#endif +#if (ADBDEBUG & ADBDEBUG_INPUT) + if (console_loglevel == 10) { + printk("adb_input: adb packet "); + for (i = 0; i < nb; ++i) + printk(" %x", buf[i]); + printk(", id = %d\n", id); + } +#endif + if (adb_handler[id].handler != 0) + { + (*adb_handler[id].handler)(buf, nb, regs); + } + break; + + default: +#if (ADBDEBUG & ADBDEBUG_INPUT) + if (console_loglevel == 10) { + printk("adb_input: data from via (%d bytes):", nb); + for (i = 0; i < nb; ++i) + printk(" %.2x", buf[i]); + printk("\n"); + } +#endif + } +} + +/* Ultimately this should return the number of devices with + the given default id. */ + +int adb_register(int default_id, + void (*handler)(unsigned char *, int, struct pt_regs *)) +{ + if (adb_handler[default_id].handler != 0) + panic("Two handlers for ADB device %d\n", default_id); + adb_handler[default_id].handler = handler; + return 1; +} + +/* + * /dev/adb device driver. + */ + +#define ADB_MAJOR 56 /* major number for /dev/adb */ + +#define ADB_MAX_MINOR 64 /* range of ADB minors */ +#define ADB_TYPE_SHIFT 4 /* # bits for device ID/type in subdevices */ + +#define ADB_TYPE_RAW 0 /* raw device; unbuffered */ +#define ADB_TYPE_BUFF 1 /* raw device; buffered */ +#define ADB_TYPE_COOKED 2 /* 'cooked' device */ + + +extern void adbdev_init(void); + +struct adbdev_state { + struct adb_request req; +}; + +static struct wait_queue *adb_wait; + +static int adb_wait_reply(struct adbdev_state *state, struct file *file) +{ + int ret = 0; + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&adb_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!state->req.got_reply) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&adb_wait, &wait); + + return ret; +} + +static void adb_write_done(struct adb_request *req) +{ + if (!req->got_reply) { + req->reply_len = 0; + req->got_reply = 1; + } + wake_up_interruptible(&adb_wait); +} + +struct file_operations *adb_raw[16]; +struct file_operations *adb_buffered[16]; +struct file_operations *adb_cooked[16]; + +static int adb_open(struct inode *inode, struct file *file) +{ + int adb_type, adb_subtype; + struct adbdev_state *state; + + if (MINOR(inode->i_rdev) > ADB_MAX_MINOR) + return -ENXIO; + + switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) { + case ADB_TYPE_RAW: + /* see code below */ + break; + case ADB_TYPE_BUFF: + /* TBI */ + return -ENXIO; + case ADB_TYPE_COOKED: + /* subtypes such as kbd, mouse, ... */ + adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT; + if ((file->f_op = adb_cooked[adb_subtype])) + return file->f_op->open(inode,file); + else + return -ENODEV; + } + + state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); + if (state == 0) + return -ENOMEM; + file->private_data = state; + state->req.reply_expected = 0; + return 0; +} + +static void adb_release(struct inode *inode, struct file *file) +{ + struct adbdev_state *state = file->private_data; + + if (state) { + file->private_data = NULL; + if (state->req.reply_expected && !state->req.got_reply) + if (adb_wait_reply(state, file)) + return; + kfree(state); + } + return; +} + +static int adb_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int adb_read(struct inode *inode, struct file *file, + char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2) + return -EINVAL; + if (count > sizeof(state->req.reply)) + count = sizeof(state->req.reply); + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + if (!state->req.reply_expected) + return 0; + + ret = adb_wait_reply(state, file); + if (ret) + return ret; + + state->req.reply_expected = 0; + ret = state->req.reply_len; + copy_to_user(buf, state->req.reply, ret); + + return ret; +} + +static int adb_write(struct inode *inode, struct file *file, + const char *buf, int count) +{ + int ret, i; + struct adbdev_state *state = file->private_data; + + if (count < 2 || count > sizeof(state->req.data)) + return -EINVAL; + ret = verify_area(VERIFY_READ, buf, count); + if (ret) + return ret; + + if (state->req.reply_expected && !state->req.got_reply) { + /* A previous request is still being processed. + Wait for it to finish. */ + ret = adb_wait_reply(state, file); + if (ret) + return ret; + } + + state->req.nbytes = count; + state->req.done = adb_write_done; + state->req.got_reply = 0; + copy_from_user(state->req.data, buf, count); +#if 0 + switch (adb_hardware) { + case ADB_NONE: + return -ENXIO; + case ADB_VIACUDA: + state->req.reply_expected = 1; + cuda_send_request(&state->req); + break; + default: +#endif + if (state->req.data[0] != ADB_PACKET) + return -EINVAL; + for (i = 1; i < state->req.nbytes; ++i) + state->req.data[i] = state->req.data[i+1]; + state->req.reply_expected = + ((state->req.data[0] & 0xc) == 0xc); + adb_send_request(&state->req); +#if 0 + break; + } +#endif + + return count; +} + +static struct file_operations adb_fops = { + adb_lseek, + adb_read, + adb_write, + NULL, /* no readdir */ + NULL, /* no poll yet */ + NULL, /* no ioctl yet */ + NULL, /* no mmap */ + adb_open, + adb_release +}; + +int adbdev_register(int subtype, struct file_operations *fops) +{ + if (subtype < 0 || subtype > 15) + return -EINVAL; + if (adb_cooked[subtype]) + return -EBUSY; + adb_cooked[subtype] = fops; + return 0; +} + +int adbdev_unregister(int subtype) +{ + if (subtype < 0 || subtype > 15) + return -EINVAL; + if (!adb_cooked[subtype]) + return -ENODEV; + adb_cooked[subtype] = NULL; + return 0; +} + +void adbdev_init() +{ + if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) + printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); +} + + +#if 0 /* old ADB device */ + +/* + * Here are the file operations we export for /dev/adb. + */ + +#define ADB_MINOR 140 /* /dev/adb is c 10 140 */ + +extern void adbdev_inits(void); + +struct adbdev_state { + struct adb_request req; +}; + +static struct wait_queue *adb_wait; + +static int adb_wait_reply(struct adbdev_state *state, struct file *file) +{ + int ret = 0; + struct wait_queue wait = { current, NULL }; + +#if (ADBDEBUG & ADBDEBUG_DEVICE) + printk("ADB request: wait_reply (blocking ... \n"); +#endif + + add_wait_queue(&adb_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!state->req.got_reply) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&adb_wait, &wait); + + return ret; +} + +static void adb_write_done(struct adb_request *req) +{ + if (!req->got_reply) { + req->reply_len = 0; + req->got_reply = 1; + } + wake_up_interruptible(&adb_wait); +} + +static int adb_open(struct inode *inode, struct file *file) +{ + struct adbdev_state *state; + + state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); + if (state == 0) + return -ENOMEM; + file->private_data = state; + state->req.reply_expected = 0; + return 0; +} + +static void adb_release(struct inode *inode, struct file *file) +{ + struct adbdev_state *state = file->private_data; + + if (state) { + file->private_data = NULL; + if (state->req.reply_expected && !state->req.got_reply) + if (adb_wait_reply(state, file)) + return; + kfree(state); + } + return; +} + +static int adb_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int adb_read(struct inode *inode, struct file *file, + char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2) + return -EINVAL; + if (count > sizeof(state->req.reply)) + count = sizeof(state->req.reply); + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + if (!state->req.reply_expected) + return 0; + + ret = adb_wait_reply(state, file); + if (ret) + return ret; + + ret = state->req.reply_len; + memcpy_tofs(buf, state->req.reply, ret); + state->req.reply_expected = 0; + + return ret; +} + +static int adb_write(struct inode *inode, struct file *file, + const char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2 || count > sizeof(state->req.data)) + return -EINVAL; + ret = verify_area(VERIFY_READ, buf, count); + if (ret) + return ret; + + if (state->req.reply_expected && !state->req.got_reply) { + /* A previous request is still being processed. + Wait for it to finish. */ + ret = adb_wait_reply(state, file); + if (ret) + return ret; + } + + state->req.nbytes = count; + state->req.done = adb_write_done; + memcpy_fromfs(state->req.data, buf, count); + state->req.reply_expected = 1; + state->req.got_reply = 0; + adb_send_request(&state->req); + + return count; +} + +static struct file_operations adb_fops = { + adb_lseek, + adb_read, + adb_write, + NULL, /* no readdir */ + NULL, /* no select */ + NULL, /* no ioctl */ + NULL, /* no mmap */ + adb_open, + adb_release +}; + +static struct miscdevice adb_dev = { + ADB_MINOR, + "adb", + &adb_fops +}; + +void adbdev_init(void) +{ + misc_register(&adb_dev); +} + +#endif /* old ADB device */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/bootparse.c linux/arch/m68k/mac/bootparse.c --- v2.1.86/linux/arch/m68k/mac/bootparse.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/bootparse.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +/* + * Booter vars + */ + +int boothowto; +int _boothowto; + +/* + * Called early to parse the environment (passed to us from the booter) + * into a bootinfo struct. Will die as soon as we have our own booter + */ + +#define atol(x) simple_strtoul(x,NULL,0) + +void parse_booter(char *env) +{ + char *name; + char *value; +#if 0 + while(0 && *env) +#else + while(*env) +#endif + { + name=env; + value=name; + while(*value!='='&&*value) + value++; + if(*value=='=') + *value++=0; + env=value; + while(*env) + env++; + env++; +#if 0 + if(strcmp(name,"VIDEO_ADDR")==0) + mac_mch.videoaddr=atol(value); + if(strcmp(name,"ROW_BYTES")==0) + mac_mch.videorow=atol(value); + if(strcmp(name,"SCREEN_DEPTH")==0) + mac_mch.videodepth=atol(value); + if(strcmp(name,"DIMENSIONS")==0) + mac_mch.dimensions=atol(value); +#endif + if(strcmp(name,"BOOTTIME")==0) + mac_bi_data.boottime=atol(value); + if(strcmp(name,"GMTBIAS")==0) + mac_bi_data.gmtbias=atol(value); + if(strcmp(name,"BOOTERVER")==0) + mac_bi_data.bootver=atol(value); + if(strcmp(name,"MACOS_VIDEO")==0) + mac_bi_data.videological=atol(value); + if(strcmp(name,"MACOS_SCC")==0) + mac_bi_data.sccbase=atol(value); + if(strcmp(name,"MACHINEID")==0) + mac_bi_data.id=atol(value); + if(strcmp(name,"MEMSIZE")==0) + mac_bi_data.memsize=atol(value); + if(strcmp(name,"SERIAL_MODEM_FLAGS")==0) + mac_bi_data.serialmf=atol(value); + if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0) + mac_bi_data.serialhsk=atol(value); + if(strcmp(name,"SERIAL_MODEM_GPICLK")==0) + mac_bi_data.serialgpi=atol(value); + if(strcmp(name,"SERIAL_PRINT_FLAGS")==0) + mac_bi_data.printmf=atol(value); + if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0) + mac_bi_data.printhsk=atol(value); + if(strcmp(name,"SERIAL_PRINT_GPICLK")==0) + mac_bi_data.printgpi=atol(value); + if(strcmp(name,"PROCESSOR")==0) + mac_bi_data.cpuid=atol(value); + if(strcmp(name,"ROMBASE")==0) + mac_bi_data.rombase=atol(value); + if(strcmp(name,"TIMEDBRA")==0) + mac_bi_data.timedbra=atol(value); + if(strcmp(name,"ADBDELAY")==0) + mac_bi_data.adbdelay=atol(value); + } +#if 0 /* XXX: TODO with m68k_mach_* */ + /* Fill in the base stuff */ + boot_info.machtype=MACH_MAC; + /* Read this from the macinfo we got ! */ +/* boot_info.cputype=CPU_68020|FPUB_68881;*/ +/* boot_info.memory[0].addr=0;*/ +/* boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/ + boot_info.num_memory=1; /* On a MacII */ + boot_info.ramdisk_size=0; /* For now */ + *boot_info.command_line=0; +#endif + } + + +void print_booter(char *env) +{ + char *name; + char *value; + while(*env) + { + name=env; + value=name; + while(*value!='='&&*value) + value++; + if(*value=='=') + *value++=0; + env=value; + while(*env) + env++; + env++; + printk("%s=%s\n", name,value); + } + } + + diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c --- v2.1.86/linux/arch/m68k/mac/config.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/config.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,575 @@ +/* + * linux/arch/m68k/mac/config.c + * + * 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. + */ + +/* + * Miscellaneous linux stuff + */ + +#include +#include +#include +#include +#include +#include +#include +/* keyb */ +#include +#include +/* keyb */ +#include + +#define BOOTINFO_COMPAT_1_0 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "via6522.h" + +/* old bootinfo stuff */ + +struct mac_booter_data mac_bi_data = {0,}; +int mac_bisize = sizeof mac_bi_data; + +struct compat_bootinfo compat_boot_info ={0,}; +int compat_bisize = sizeof compat_boot_info; + +int compat_bi = 0; + +/* New bootinfo stuff */ + +extern int m68k_num_memory; +extern struct mem_info m68k_memory[NUM_MEMINFO]; + +extern struct mem_info m68k_ramdisk; + +extern char m68k_command_line[CL_SIZE]; + +void *mac_env; /* Loaded by the boot asm */ + +extern int mac_keyb_init(void); +extern int mac_kbdrate(struct kbd_repeat *k); +extern void mac_kbd_leds(unsigned int leds); + +extern void (*kd_mksound)(unsigned int, unsigned int); +extern void mac_mksound(unsigned int, unsigned int); +extern int mac_floppy_init(void); +extern void mac_floppy_setup(char *,int *); + +extern void mac_gettod (int *, int *, int *, int *, int *, int *); + +extern void nubus_sweep_video(void); +extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); +extern void mac_debugging_long(int, long); + +/* Mac specific debug functions (in debug.c) */ +extern void mac_debug_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +static char mac_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */ + "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\000\000\000()/*789456123" /* 0x60 - 0x6f */ + "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif + +extern void (*kd_mksound)(unsigned int, unsigned int); + +void mac_get_model(char *str) +{ + strcpy(str,"Macintosh"); +} + +void mac_bang(int irq, void *vector, struct pt_regs *p) +{ + printk("Resetting ...\n"); + mac_reset(); +} + +void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) +{ + via_init_clock(vector); +} + +unsigned long mac_gettimeoffset (void) +{ + return 0L; +} + +extern int console_loglevel; + +void mac_gettod (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, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 }; + + time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */ + +#if 0 + printk("mac_gettod: boottime 0x%lx gmtbias %ld \n", + mac_bi_data.boottime, mac_bi_data.gmtbias); +#endif + + *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 */ + /* 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] = 28; + + /* count the months */ + for (*monp = 1; time > mon_days[*monp]; (*monp)++) + time -= mon_days[*monp]; + + *dayp = time; + +#if 1 + printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n", + *yearp, *monp, *dayp, *hourp, *minp, *secp, + (signed long) mac_bi_data.gmtbias); +#endif + + return; +} + +void mac_waitbut (void) +{ + ; +} + +extern struct consw fb_con; +extern struct fb_info *mac_fb_init(long *); +extern void mac_video_setup(char *, int *); + +void mac_debug_init (void) +{ + ; +} + +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 + */ + +__initfunc(int mac_parse_bootinfo(const struct bi_record *record)) +{ + int unknown = 0; + const u_long *data = record->data; + + if (compat_bi) + return(unknown); + + switch (record->tag) { + case BI_MAC_MODEL: + mac_bi_data.id = *data; + break; + case BI_MAC_VADDR: + mac_bi_data.videoaddr = *data; + break; + case BI_MAC_VDEPTH: + mac_bi_data.videodepth = *data; + break; + case BI_MAC_VROW: + mac_bi_data.videorow = *data; + break; + case BI_MAC_VDIM: + mac_bi_data.dimensions = *data; + break; + case BI_MAC_VLOGICAL: + mac_bi_data.videological = *data; + break; + case BI_MAC_SCCBASE: + mac_bi_data.sccbase = *data; + break; + case BI_MAC_BTIME: + mac_bi_data.boottime = *data; + break; + case BI_MAC_GMTBIAS: + mac_bi_data.gmtbias = *data; + break; + case BI_MAC_MEMSIZE: + mac_bi_data.memsize = *data; + break; + case BI_MAC_CPUID: + mac_bi_data.cpuid = *data; + break; + default: + unknown = 1; + } + return(unknown); +} + +__initfunc(void mac_copy_compat(void)) +{ + int i; + + compat_bi = 1; + + for (i=0; i NetBSD booter was used! */ + /* XXX FIXME: breaks for model > 31 */ + model=(mac_bi_data.cpuid>>2)&63; + 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) + break; + m++; + } + if(m->ident==-1) + { + printk("\nUnknown macintosh model %d, probably unsupported.\n", + model); + mac_debugging_long(1, (long) 0x55555555); + mac_debugging_long(1, (long) 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) + mac_boom(5); + } + + /* + * Report booter data: + */ + printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi); + printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n", + mac_bi_data.videoaddr, mac_bi_data.videorow, + mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, + mac_bi_data.dimensions >> 16); + printk (" Boottime: 0x%lx GMTBias: 0x%lx \n", + mac_bi_data.boottime, mac_bi_data.gmtbias); + printk (" Videological 0x%lx, SCC at 0x%lx \n", + mac_bi_data.videological, mac_bi_data.sccbase); + printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", + mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); + printk ("Ramdisk: addr 0x%lx size 0x%lx\n", + m68k_ramdisk.addr, m68k_ramdisk.size); + + /* + * Save the pointer + */ + + macintosh_config=m; + + /* + * TODO: set the various fields in macintosh_config->hw_present here! + */ + +} + +void mac_report_hardware(void) +{ + printk("Apple Macintosh %s\n", macintosh_config->name); +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c --- v2.1.86/linux/arch/m68k/mac/debug.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/debug.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,366 @@ +/* + * linux/arch/m68k/mac/debug.c + * + * Shamelessly stolen (SCC code and general framework) from: + * + * linux/arch/m68k/atari/debug.c + * + * Atari debugging and serial console stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * 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 + +#define BOOTINFO_COMPAT_1_0 +#include +#include +#include +#include + +extern char m68k_debug_device[]; + +extern struct compat_bootinfo compat_boot_info; + +extern unsigned long mac_videobase; +extern unsigned long mac_videodepth; +extern unsigned long mac_rowbytes; + +/* + * These two auxiliary debug functions should go away ASAP. Only usage: + * before the console output is up (after head.S come some other crucial + * setup routines :-) it permits writing 'data' to the screen as bit patterns + * (good luck reading those). Helped to figure that the bootinfo contained + * garbage data on the amount and size of memory chunks ... + * + * The 'pos' argument now simply means 'linefeed after print' ... + */ + +static int peng=0, line=0; + +void mac_debugging_short(int pos, short num) +{ + unsigned char *pengoffset; + unsigned char *pptr; + int i; + + if (!MACH_IS_MAC) { + /* printk("debug: %d !\n", num); */ + return; + } + + /* calculate current offset */ + pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes) + +80*peng; + + pptr=pengoffset; + + for(i=0;i<8*sizeof(short);i++) /* # of bits */ + { + /* value mask for bit i, reverse order */ + *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00); + } + + peng++; + + if (pos) { + line++; + peng = 0; + } +} + +void mac_debugging_long(int pos, long addr) +{ + unsigned char *pengoffset; + unsigned char *pptr; + int i; + + if (!MACH_IS_MAC) { + /* printk("debug: #%ld !\n", addr); */ + return; + } + + pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes) + +80*peng; + + pptr=pengoffset; + + for(i=0;i<8*sizeof(long);i++) /* # of bits */ + { + *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00); + } + + peng++; + + if (pos) { + line++; + peng = 0; + } +} + +/* + * Penguin - used by head.S console; obsolete + */ +char that_penguin[]={ +#include "that_penguin.h" +}; + +/* + * B/W version of penguin, unfinished - any takers?? + */ +static char bw_penguin[]={ +#include "bw_penguin.h" +}; + +void mac_debugging_penguin(int peng) +{ + unsigned char *pengoffset; + unsigned char *pptr; + unsigned char *bwpdptr=bw_penguin; + int i; + + if (!MACH_IS_MAC) + return; + + if (compat_boot_info.bi_mac.videodepth ==1) + pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes) + +5*peng; + else + pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes) + +20*peng; + + pptr=pengoffset; + + for(i=0;i<36;i++) + { + memcpy(pptr,bwpdptr,4); + bwpdptr+=4; + pptr+=mac_rowbytes; + } +} + +/* + * B/W version of flaming Mac, unfinished (see above). + */ +static char bw_kaboom_map[]={ +#include "bw_mac.h" +}; + +static void mac_boom_boom(void) +{ + static unsigned char *boomoffset=NULL; + unsigned char *pptr; + unsigned char *bwpdptr=bw_kaboom_map; + int i; + + if(!boomoffset) + if (compat_boot_info.bi_mac.videodepth == 1) { + boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes); + } else { + boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes); + } + else + if (compat_boot_info.bi_mac.videodepth == 1) + boomoffset+=5; + else + boomoffset+=32; + + pptr=boomoffset; + + for(i=0;i<36;i++) + { + memcpy(pptr,bwpdptr,4); + bwpdptr+=4; + pptr+=mac_rowbytes; + } +} + +void mac_boom(int booms) +{ + int i; + + if (!MACH_IS_MAC) + return; + + for(i=0;i 0; --i ) \ + MFPDELAY(); \ + } while(0) + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void mac_init_scc_port( int cflag, int port )) +#else +void mac_init_scc_port( int cflag, int port ) +#endif +{ + extern int mac_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCC_WRITE( 3, reg3 ); + SCC_WRITE( 5, reg5 ); + SCC_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 10, 0 ); /* NRZ mode */ + SCC_WRITE( 11, clksrc ); /* main clock source */ + SCC_WRITE( 12, div ); /* BRG value */ + SCC_WRITE( 13, 0 ); /* BRG high byte */ + SCC_WRITE( 14, brgsrc_table[baud] ); + SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCC_WRITE( 3, reg3 | 1 ); + SCC_WRITE( 5, reg5 | 8 ); + + mac_SCC_reset_done = 1; + mac_SCC_init_done = 1; +} + + +__initfunc(void mac_debug_init(void)) +{ +#ifdef CONFIG_KGDB + /* the m68k_debug_device is used by the GDB stub, do nothing here */ + return; +#endif + if (!strcmp( m68k_debug_device, "ser" )) { + strcpy( m68k_debug_device, "ser1" ); + } + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + mac_init_scc_port( B9600|CS8, 0 ); + mac_console_driver.write = mac_scc_console_write; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + mac_init_scc_port( B9600|CS8, 1 ); + mac_console_driver.write = mac_scc_console_write; + } + if (mac_console_driver.write) + register_console(&mac_console_driver); +} +#endif + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/ksyms.c linux/arch/m68k/mac/ksyms.c --- v2.1.86/linux/arch/m68k/mac/ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/ksyms.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,7 @@ +#include +#include +#include +/* Hook for mouse driver */ +extern void (*mac_mouse_interrupt_hook) (char *); + +EXPORT_SYMBOL(mac_mouse_interrupt_hook); diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/macboing.c linux/arch/m68k/mac/macboing.c --- v2.1.86/linux/arch/m68k/mac/macboing.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/macboing.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,92 @@ +/* + * Mac bong noise generator. Note - we ought to put a boingy noise + * here 8) + */ + +#include +#include + +#include +#include + +static const signed char sine_data[] = { + 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, + 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 +}; +#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0])) + +static void nosound( unsigned long ignored ); +static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound }; + +static volatile unsigned char *asc_base=(void *)0x50F14000; + + +void mac_mksound( unsigned int hz, unsigned int ticks ) +{ + static int inited = 0; + unsigned long flags; + int samples=512; + + if(!inited) + { + int i=0; + int j=0; + int k=0; + int l=0; + for(i=0;i 20 && hz < 32767) { + int i; + u_long asc_pulses=((hz<<5)*samples)/468; + for(i=0;i<4;i++) + { + asc_base[ASC_FREQ(i,0)]=0x00; + asc_base[ASC_FREQ(i,1)]=20; + asc_base[ASC_FREQ(i,2)]=0x00; + asc_base[ASC_FREQ(i,3)]=20; + asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF; + asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF; + asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF; + asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF; + } + asc_base[ASC_CHAN]=0x03; + asc_base[ASC_VOLUME]=128; + asc_base[ASC_MODE]=ASC_MODE_SAMPLE; + asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE; + if (ticks) { + sound_timer.expires = jiffies + ticks; + add_timer( &sound_timer ); + } + } else { + nosound( 0 ); + } + restore_flags(flags); +} + + +static void nosound( unsigned long ignored ) +{ + asc_base[ASC_ENABLE]=0; +} diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c --- v2.1.86/linux/arch/m68k/mac/macints.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/macints.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,979 @@ +/* + * Macintosh interrupts + * + * General design: + * In contrary to the Amiga and Atari platforms, the Mac hardware seems to + * exclusively use the autovector interrupts (the 'generic level0-level7' + * interrupts with exception vectors 0x19-0x1f). The following interrupt levels + * are used: + * 1 - VIA1 + * - slot 0: one second interrupt + * - slot 1: VBlank + * - slot 2: ADB data ready (SR full) + * - slot 3: ADB data (CB2) + * - slot 4: ADB clock (CB1) + * - slot 5: timer 2 + * - 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 + * + * 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!). + * + */ + +#include +#include +#include +#include +#include /* for intr_count */ + +#include +#include +#include +#include +#include +#include "via6522.h" + +#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 scc_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 scc_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. + */ + +static struct irqflags irq_flags[8]; + +/* + * This array holds the pointers to the various VIA or other interrupt + * controllers + */ + +static volatile unsigned char *via_table[8]; + +#ifdef VIABASE_WEIRDNESS +/* + * VIA2 / RBV default base address + */ + +volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS); +volatile unsigned char *rbv_regp = ((volatile unsigned char *)VIA2_BAS_IIci); +#endif + +/* + * Flags to control via2 / rbv behaviour + */ + +static int via2_is_rbv = 0; +static int rbv_clear = 0; + +/* + * console_loglevel determines NMI handler function + */ + +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); + +static void via_do_nubus(int slot, void *via, struct pt_regs *regs); + +/*#define DEBUG_VIA*/ + +void mac_init_IRQ(void) +{ + int i; + + mac_debugging_penguin(6); + +#ifdef DEBUG_MACINTS + printk("Mac interrupt stuff initializing ...\n"); +#endif + /* 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) { + /* 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! + */ +#if 0 /* doesn't seem to work yet */ + sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler); +#else + sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler); +#endif + /* Alan uses IRQ 5 for SCC ?? */ + sys_request_irq(5, mac_debug_handler, IRQ_FLG_STD, "INT5", 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]; + + if (via2_is_rbv) { + via_table[1] = rbv_regp; + handler_table[1] = &rbv_handler[0]; + param_table[1] = &rbv_param[0]; + } else { + via_table[1] = via2_regp; + handler_table[1] = &via2_handler[0]; + param_table[1] = &via2_param[0]; + } + via_table[2] = NULL; + via_table[3] = NULL; + + handler_table[2] = &rbv_handler[0]; + handler_table[3] = &nubus_handler[0]; + + param_table[2] = &rbv_param[0]; + param_table[3] = &nubus_param[0]; + + mac_debugging_penguin(7); +#ifdef DEBUG_MACINTS + printk("Mac interrupt init 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. + */ + +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 */ + if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) { + /* 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; + } + + 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 ... */ + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); + 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?) + */ + via_write(via, vPCR, 0x66); + } + + return 0; +} + +void mac_free_irq (unsigned int irq, void *dev_id) +{ + 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; + +#ifdef DEBUG_MACINTS + printk ("%s: IRQ %d on VIA%d[%d] freed\n", + __FUNCTION__, irq, srcidx+1, irqidx); +#endif + + /* 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); + cli(); + + /* figure out if SCC pseudo-irq */ + if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) { + /* 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; + } + + 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; + } + + /* 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<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + irq_flags[srcidx].disabled &= ~(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + irq_flags[srcidx].disabled |= (1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + volatile unsigned char *via; + + via = (volatile unsigned char *) via_table[srcidx]; + if (!via) + return; + + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); + else + via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); + +} + +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; + + via = (volatile unsigned char *) via_table[srcidx]; + if (!via) + return; + + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, (via_read(via, rIER)&(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + irq_flags[srcidx].pending &= ~(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + return (irq_flags[srcidx].pending & (1<= 8 ) { +#if 0 + show_state(); + printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); + printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + + if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) + printk("Corrupted stack page\n"); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, current->kernel_stack_page); + if (intr_count == 1) + dump_stack((struct frame *)fp); +#else + /* printk("NMI "); */ +#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]; + + /* 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) + { + printk("via_irq: nothing pending!\n"); + 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) + { + printk("via%d: stuck events %x\n", (*viaidx)+1, events); + 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]; + +#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. + */ + + /* shouldn't we disable interrupts here ?? */ + + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("rbv_irq: nothing pending!\n"); + return; + } + + 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<2) + { + printk("nubus stuck events - %d/%d\n", map, nubus_active); + return; + } + + for(i=0;i<7;i++) + { + if(map&(1< +#include +#include +#include +#include +#include +#include +/* keyb */ +#include +#include +#include +/* keyb */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +/* for keyboard_input stuff */ +#include +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ +/* end keyboard_input stuff */ + +#include +#include +#include + +static void kbd_repeat(unsigned long); +static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; +static int last_keycode; + +static void input_keycode(int, int); + +extern struct kbd_struct kbd_table[]; + +extern void handle_scancode(unsigned char); +extern void put_queue(int); + +/* keyb */ +static void mac_leds_done(struct adb_request *); +static void keyboard_input(unsigned char *, int, struct pt_regs *); +static void mouse_input(unsigned char *, int, struct pt_regs *); +/* Hook for mouse driver */ +void (*mac_mouse_interrupt_hook) (char *); +int mac_emulate_button2; +int mac_emulate_button3; +/* The mouse driver - for debugging */ +extern void mac_mouse_interrupt(char *); +/* end keyb */ + +/* this map indicates which keys shouldn't autorepeat. */ +static unsigned char dont_repeat[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* + * Mac private key maps + */ +u_short mac_plain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_shift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_altgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_shift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, +}; + +u_short mac_alt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_ctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +extern unsigned int keymap_count; + +#if 0 +ushort *mac_key_maps[MAX_NR_KEYMAPS] = { + mac_plain_map, mac_shift_map, mac_altgr_map, 0, + mac_ctrl_map, mac_shift_ctrl_map, 0, 0, + mac_alt_map, 0, 0, 0, + mac_ctrl_alt_map, 0 +}; +#endif + +/* + * Misc. defines for testing + */ + +extern int console_loglevel; + +static struct adb_request led_request; +extern int in_keybinit; + +/* + * machdep keyboard routines, interface and key repeat method modeled after + * drivers/macintosh/keyb_mac.c + */ + +int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode) +{ + if (!raw_mode) { + /* + * Convert R-shift/control/option to L version. + * Remap keycode 0 (A) to the unused keycode 0x5a. + * Other parts of the system assume 0 is not a valid keycode. + */ + switch (keycode) { + case 0x7b: keycode = 0x38; break; /* R-shift */ + case 0x7c: keycode = 0x3a; break; /* R-option */ + case 0x7d: keycode = 0x36; break; /* R-control */ + case 0: keycode = 0x5a; break; /* A */ + } + } + *keycodep = keycode; + return 1; +} + +int mac_kbd_unexpected_up(unsigned char keycode) +{ + return 0x80; +} + +static void +keyboard_input(unsigned char *data, int nb, struct pt_regs *regs) +{ + /* first check this is from register 0 */ + if (nb != 5 || (data[2] & 3) != KEYB_KEYREG) + return; /* ignore it */ + kbd_pt_regs = regs; + input_keycode(data[3], 0); + if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f))) + input_keycode(data[4], 0); +} + +static void +input_keycode(int keycode, int repeat) +{ + struct kbd_struct *kbd; + int up_flag; + + kbd = kbd_table + fg_console; + up_flag = (keycode & 0x80); + keycode &= 0x7f; + if (!repeat) + del_timer(&repeat_timer); + + /* + * XXX: Add mouse button 2+3 fake codes here if mouse open. + * As we only report up/down events, keep track of faked buttons. + * Really messy; might need to check if keyboard is in + * VC_RAW mode for X?. + * Might also want to know how many buttons need to be emulated. + * -> hide this as function in arch/m68k/mac ? + * Current emulation buttons: right alt/option and control + * (wanted: command and alt/option, or KP= and KP( ...) + * Debug version; might be rewritten to be faster on normal keys. + */ + if (mac_mouse_interrupt_hook || console_loglevel >= 8) { + unsigned char button, button2, button3, fake_event; + static unsigned char button2state=0, button3state=0; /* up */ + /* faked ADB packet: device type ff, handler 4 ! */ + static char data[6] = { 0xff, 0x40, 0x3c, 0x80, 0x80, 0x80 }; + + button = 0; + fake_event = 0; + switch (keycode) { /* which 'button' ? */ + case 0x7c: /* R-option */ + button2 = (!up_flag); /* new state */ + if (button2 != button2state) /* change ? */ + button = 2; + button2state = button2; /* save state */ + fake_event = 2; + break; + case 0x7d: /* R-control */ + button3 = (!up_flag); /* new state */ + if (button3 != button3state) /* change ? */ + button = 3; + button3state = button3; /* save state */ + fake_event = 3; + break; + } +#ifdef DEBUG_ADBMOUSE + if (fake_event && console_loglevel >= 8) + printk("fake event: button2 %d button3 %d button %d\n", + button2state, button3state, button); +#endif + if (button) { /* there's been a button state change */ + /* fake a mouse packet : send all bytes, change one! */ + data[button+2] = (up_flag ? 0x80 : 0); + if (mac_mouse_interrupt_hook) + mac_mouse_interrupt_hook(data); +#ifdef DEBUG_ADBMOUSE + else + printk("mouse_fake: data %2x %2x %2x buttons %2x \n", + data[3], data[4], data[5], + ~( (data[3] & 0x80 ? 0 : 4) + | (data[4] & 0x80 ? 0 : 1) + | (data[5] & 0x80 ? 0 : 2) )&7 ); +#endif + } + /* + * for mouse 3-button emulation: don't process 'fake' keys! + * Keys might autorepeat, and console state gets generally messed + * up enough so that selection stops working. + */ + if (fake_event) + return; + } + + /* + * Convert R-shift/control/option to L version. + */ + switch (keycode) { + case 0x7b: keycode = 0x38; break; /* R-shift */ + case 0x7c: keycode = 0x3a; break; /* R-option */ + case 0x7d: keycode = 0x36; break; /* R-control */ + case 0x0: if (kbd->kbdmode != VC_RAW) + keycode = 0x5a; /* A; keycode 0 deprecated */ + break; + } + + if (kbd->kbdmode != VC_RAW) { + if (!up_flag && !dont_repeat[keycode]) { + last_keycode = keycode; + repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2); + add_timer(&repeat_timer); + } + + /* + * XXX fix caps-lock behaviour by turning the key-up + * transition into a key-down transition. + * MSch: need to turn each caps-lock event into a down-up + * double event (keyboard code assumes caps-lock is a toggle) + */ +#if 0 + if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK)) + up_flag = 0; +#else + if (keycode == 0x39) { + handle_scancode(keycode); /* down */ + up_flag = 0x80; /* see below ... */ + } +#endif + } + + handle_scancode(keycode + up_flag); +} + +static void +kbd_repeat(unsigned long xxx) +{ + unsigned long flags; + + save_flags(flags); + cli(); + input_keycode(last_keycode, 1); + restore_flags(flags); +} + + /* [ACA:23-Mar-97] Three button mouse support. This is designed to + function with MkLinux DR-2.1 style X servers. It only works with + three-button mice that conform to Apple's multi-button mouse + protocol. */ + + /* + The X server for MkLinux DR2.1 uses the following unused keycodes to + read the mouse: + + 0x7e This indicates that the next two keycodes should be interpreted + as mouse information. The first following byte's high bit + represents the state of the left button. The lower seven bits + represent the x-axis acceleration. The lower seven bits of the + second byte represent y-axis acceleration. + + 0x3f The x server interprets this keycode as a middle button + release. + + 0xbf The x server interprets this keycode as a middle button + depress. + + 0x40 The x server interprets this keycode as a right button + release. + + 0xc0 The x server interprets this keycode as a right button + depress. + + NOTES: There should be a better way of handling mice in the X server. + The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead + of two. The three mouse buttons should then, in the X server, be read + as the high-bits of all three bytes. The x and y motions can still be + in the first two bytes. Maybe I'll do this... + */ + + /* + Handler 4 -- Apple Extended mouse protocol. + + For Apple's 3-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = 0000 0000 ADB packet identifer. + data[1] = 0100 0000 Extended protocol register. + Bits 6-7 are the device id, which should be 1. + Bits 4-5 are resolution which is in "units/inch". + The Logitech MouseMan returns these bits clear but it has + 200/300cpi resolution. + Bits 0-3 are unique vendor id. + data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. + Bits 2-3 should be 8 + 4. + Bits 4-7 should be 3 for a mouse device. + data[3] = bxxx xxxx Left button and x-axis motion. + data[4] = byyy yyyy Second button and y-axis motion. + data[5] = byyy bxxx Third button and fourth button. Y is additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + + NOTE: data[0] and data[2] are confirmed by the parent function and + need not be checked here. + */ + + /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = 0000 0000 ADB packet identifer. + data[1] = ???? ???? (?) + data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. + data[3] = bxxx xxxx First button and x-axis motion. + data[4] = byyy yyyy Second button and y-axis motion. + + NOTE: data[0] is confirmed by the parent function and need not be + checked here. + */ + +static void +mouse_input(unsigned char *data, int nb, struct pt_regs *regs) +{ + struct kbd_struct *kbd; + int i; + + if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) { + printk("data from mouse:"); + for (i = 0; i < nb; ++i) + printk(" %x", data[i]); + printk("\n"); + return; + } + + if (mac_mouse_interrupt_hook) { + mac_mouse_interrupt_hook(data); + /* + * passing the mouse data to i.e. the X server as done for + * Xpmac will confuse applications on a sane X server :-) + */ + return; + } +#ifdef DEBUG_ADBMOUSE + else + if (console_loglevel >= 8) + printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", + data[3], data[4], data[5], + ~((data[3] & 0x80 ? 0 : 4) + | (data[4] & 0x80 ? 0 : 1) + | (data[5] & 0x80 ? 0 : 2))&7, + ((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ), + ((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) ); +#endif + + + kbd = kbd_table + fg_console; + +#if 0 /* The entirely insane way of MkLinux handling mouse input */ + /* Requires put_queue which is static in keyboard.c :-( */ + /* Only send mouse codes when keyboard is in raw mode. */ + if (kbd->kbdmode == VC_RAW) { + static unsigned char uch_ButtonStateSecond = 0; + unsigned char uchButtonSecond; + + /* Send first button, second button and movement. */ + put_queue( 0x7e ); + put_queue( data[3] ); + put_queue( data[4] ); + + /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ + + /* Store the button state. */ + uchButtonSecond = (data[4] & 0x80); + + /* Send second button. */ + if (uchButtonSecond != uch_ButtonStateSecond) { + put_queue( 0x3f | uchButtonSecond ); + uch_ButtonStateSecond = uchButtonSecond; + } + + /* Macintosh 3-button mouse (handler 4). */ + if ((nb == 6) && (data[1] & 0x40)) { + static unsigned char uch_ButtonStateThird = 0; + unsigned char uchButtonThird; + + /* Store the button state for speed. */ + uchButtonThird = (data[5] & 0x80); + + /* Send third button. */ + if (uchButtonThird != uch_ButtonStateThird) { + put_queue( 0x40 | uchButtonThird ); + uch_ButtonStateThird = uchButtonThird; + } + } + } +#endif /* insane MkLinux mouse hack */ +} + +/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ +static unsigned char mac_ledmap[8] = { + 0, /* none */ + 4, /* scroll lock */ + 1, /* num lock */ + 5, /* scroll + num lock */ + 2, /* caps lock */ + 6, /* caps + scroll lock */ + 3, /* caps + num lock */ + 7, /* caps + num + scroll lock */ +}; + +static int leds_pending; + +void mac_kbd_leds(unsigned int leds) +{ + if (led_request.got_reply) { +#ifdef DEBUG_ADB + if (console_loglevel == 10) + printk("mac_kbd_leds: got reply, sending request!\n"); +#endif + adb_request(&led_request, mac_leds_done, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), + 0xff, ~mac_ledmap[leds]); + } else + leds_pending = leds | 0x100; +} + +static void mac_leds_done(struct adb_request *req) +{ + int leds; + + if (leds_pending) { + leds = leds_pending & 0xff; + leds_pending = 0; + mac_kbd_leds(leds); + } + mark_bh(KEYBOARD_BH); +} + +int mac_kbdrate(struct kbd_repeat *k) +{ + return 0; +} + +int mac_keyb_init(void) +{ + static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req; + volatile int ct; + + /* setup key map */ + key_maps[0] = mac_plain_map; + key_maps[1] = mac_shift_map; + key_maps[2] = mac_altgr_map; + key_maps[4] = mac_ctrl_map; + key_maps[5] = mac_shift_ctrl_map; + key_maps[8] = mac_alt_map; + /* key_maps[9] = atashift_alt_map; */ + key_maps[12] = mac_ctrl_alt_map; + /* key_maps[13] = atashift_ctrl_alt_map; */ + memcpy (plain_map, mac_plain_map, sizeof(plain_map)); + keymap_count = 7; + + /* initialize mouse interrupt hook */ + mac_mouse_interrupt_hook = NULL; + /* assume broken mouse :-) */ + mac_emulate_button2 = 1; + mac_emulate_button3 = 1; + + /* + * Might put that someplace else, possibly .... + */ + adb_bus_init(); + + /* the input functions ... */ + adb_register(ADB_KEYBOARD, keyboard_input); + adb_register(ADB_MOUSE, mouse_input); + + /* turn on ADB auto-polling in the CUDA */ + + /* + * Older boxes don't support CUDA_* targets and CUDA commands + * instead we emulate them in the adb_request hook to make + * the code interfaces saner. + * + * Note XXX: the Linux PMac and this code both assume the + * devices are at their primary ids and do not do device + * assignment. This isn't ideal. We should fix it to follow + * the reassignment specs. + */ + + if (macintosh_config->adb_type == MAC_ADB_CUDA) { + printk("CUDA autopoll on ...\n"); + adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); + ct=0; + while (!autopoll_req.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Keyboard timed out.\n"); + } + + /* + * XXX: all ADB requests now in CUDA format; adb_request takes + * care of that for other Macs. + */ + + printk("Configuring keyboard\n"); + + /* + * turn on all leds - the keyboard driver will turn them back off + * via mac_kbd_leds if everything works ok! + */ + printk("leds on ...\n"); + adb_request(&led_request, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7); + + /* + * The polling stuff should go away as soon as the ADB driver is stable + */ + ct = 0; + adb_poll(); + while (!led_request.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Keyboard timed out.\n"); + +#if 1 + printk("Configuring coding mode ...\n"); + + /* + * get the keyboard to send separate codes for + * left and right shift, control, option keys. + */ + adb_request(&confcod_req, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); + + ct=0; + adb_poll(); + while (!confcod_req.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Keyboard timed out.\n"); +#endif + +#if 0 /* seems to hurt, at least Geert's Mac */ + printk("Configuring mouse (3-button mode) ...\n"); + + /* + * XXX: taken from the PPC driver again ... + * Try to switch the mouse (id 3) to handler 4, for three-button + * mode. (0x20 is Service Request Enable, 0x03 is Device ID). + */ + adb_request(&mouse_req, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); + + ct=0; + adb_poll(); + while (!mouse_req.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Mouse timed out.\n"); +#endif + +#if 0 + printk("Start polling keyboard ...\n"); + + /* + * get the keyboard to send data back, via the adb_input hook + * XXX: was never used properly, and the driver takes care + * of polling and timeout retransmits now. + * Might be of use if we want to start talking to a specific + * device here... + */ + adb_request(&readkey_req, NULL, 2, ADB_PACKET, + ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG)); +#endif + + /* + * fake 'request done' for the driver if requests timed out + */ + + autopoll_req.got_reply = 1; +#if 0 + /* XXX: results in race and hang with mac_kbd_leds and serial (why ?) */ + led_request.got_reply = 1; +#endif + confcod_req.got_reply = 1; + + in_keybinit = 0; + printk("Keyboard init done\n"); + + return 0; +} diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c --- v2.1.86/linux/arch/m68k/mac/via6522.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/via6522.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,591 @@ + +/* + * 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 "via6522.h" + +volatile unsigned char *via1=(unsigned char *)VIABASE; +volatile unsigned char *via2=(unsigned char *)VIABASE2; + +unsigned char via1_clock, via1_datab; + +static int rbv=0; + +/* + * Debugging the VBL ints + */ + +extern int console_loglevel; + +/* + * VIA1 - hardwired vectors + */ + +#if 0 /* gone to macints.[ch] */ +extern void via_wtf(int slot, void *via, struct pt_regs *regs); +static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs); + +extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); + +static struct via_irq_tab via1_func_tab= +{ + { + via_wtf, /* One second interrupt */ + via_wtf, /* Vblank */ + via_wtf, /* ADB data ready */ + via_wtf, /* ADB data */ + via_wtf, /* ADB clock */ + via_wtf, + via_wtf, /* Slot 6 is replaced by the timer */ + via_wtf + } +}; + +static struct via_irq_tab via2_func_tab= +{ + { + via_wtf, + via_do_nubus, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf + } +}; + +static struct via_irq_tab nubus_func_tab= +{ + { + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf + } +}; +#endif + +extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); + +#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_init_clock(void (*func)(int, void *, struct pt_regs *)) +{ + unsigned char c; + +/* mac_debugging_penguin(6);*/ + + switch(macintosh_config->via_type) + { + /* + * CI, SI, VX, LC + */ + case MAC_VIA_IIci: + via1=(void *)0x50F00000; + via2=(void *)0x50F26000; + rbv=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: + } + 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 + { + /* + * 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); + +/* mac_debugging_penguin(7);*/ + + /* + * SE/30: disable video int. + * XXX: testing for SE/30 VBL + */ + + if (macintosh_config->ident == MAC_MODEL_SE30 + && console_loglevel != 10) { + c = via_read(via1, vBufB); + via_write(via1, vBufB, c|(0x40)); + c = via_read(via1, vDirB); + via_write(via1, vDirB, c|(0x40)); + } + + /* + * XXX: use positive edge + */ + + if (console_loglevel == 10) { + c = via_read(via1, vPCR); + via_write(via1, vPCR, c|(0x1)); + } + +#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 + +} + +#if 0 /* moved to macints.c */ + +static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab, + struct pt_regs *regs) +{ + unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; + int i; + int ct=0; + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("via_irq: nothing pending!\n"); + return; + } + + do { + /* + * Clear the pending flag + */ + + /* HACK HACK - FIXME !!! - just testing some keyboard ideas */ + + /* events&=~(1<<4); */ + via_write(via, vIFR, events); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + if(events&(1<vector[i])(i, via, regs); + } + + /* + * And done.. + */ + events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; + ct++; + if(events && ct>8) + { + printk("via: stuck events %x\n",events); + break; + } + } + while(events); + + scsi_mac_polled(); +} + +/* + * + * The RBV is different. RBV appears to stand for randomly broken + * VIA. + */ + +static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab, + struct pt_regs *regs) +{ + unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; + int i; + int ct=0; + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("rbv_irq: nothing pending!\n"); + return; + } + + do { + /* + * Clear the pending flag + */ + + /* HACK HACK - FIXME !!! - just testing some keyboard ideas */ + + /* events&=~(1<<4); */ + via_write(via, rIFR, events); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + if(events&(1<vector[i])(i, via, regs); + } + + /* + * And done.. + */ + events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; + ct++; + if(events && ct>8) + { + printk("rbv: stuck events %x\n",events); + for(i=0;i<7;i++) + { + if(events&(1<2) + { + printk("nubus stuck events - %d/%d\n", map, nubus_active); + return; + } + for(i=0;i<7;i++) + { + if(map&(1<mmap_sem); - /* Are we prepared to handle this fault? */ + /* User mode accesses just cause a SIGSEGV */ + if (user_mode(regs)) { + force_sig (SIGSEGV, tsk); + return 1; + } + + /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->pc)) != 0) { struct pt_regs *tregs; - printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", - current->comm, regs->pc, fixup); /* Create a new four word stack frame, discarding the old one. */ regs->stkadj = frame_extra_sizes[regs->format]; @@ -115,12 +119,6 @@ tregs->pc = fixup; tregs->sr = regs->sr; return -1; - } - - if (user_mode(regs)) { - /* User memory access */ - force_sig (SIGSEGV, tsk); - return 1; } /* diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.1.86/linux/arch/m68k/mm/init.c Mon Jun 16 16:35:54 1997 +++ linux/arch/m68k/mm/init.c Thu Feb 12 16:30:13 1998 @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_ATARI +#include +#endif extern void die_if_kernel(char *,struct pt_regs *,long); extern void init_kpointer_table(void); @@ -63,6 +66,7 @@ { unsigned long i; int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0; + int cached = 0; printk("\nMem-info:\n"); show_free_areas(); @@ -72,6 +76,8 @@ total++; if (PageReserved(mem_map+i)) reserved++; + if (PageSwapCache(mem_map+i)) + cached++; else if (!atomic_read(&mem_map[i].count)) free++; else if (atomic_read(&mem_map[i].count) == 1) @@ -84,6 +90,7 @@ printk("%d reserved pages\n",reserved); printk("%d pages nonshared\n",nonshared); printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); show_buffers(); #ifdef CONFIG_NET show_net_buffers(); @@ -293,8 +300,6 @@ /* * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. - * The parameters are pointers to where to stick the starting and ending - * addresses of available kernel virtual memory. */ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) @@ -321,6 +326,18 @@ 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 @@ -412,42 +429,15 @@ high_memory = (void *) end_mem; max_mapnr = num_physpages = MAP_NR(end_mem); - start_mem = PAGE_ALIGN(start_mem); - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; + tmp = start_mem = PAGE_ALIGN(start_mem); + while (tmp < end_mem) { + clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags); + tmp += PAGE_SIZE; } #ifdef CONFIG_ATARI - - if (MACH_IS_ATARI) { - - /* If the page with physical address 0 isn't the first kernel - * code page, it has to be reserved because the first 2 KB of - * ST-Ram can only be accessed from supervisor mode by - * hardware. - */ - - unsigned long virt0 = PTOV( 0 ), adr; - extern unsigned long rsvd_stram_beg, rsvd_stram_end; - - if (virt0 != 0) { - - set_bit(PG_reserved, &mem_map[MAP_NR(virt0)].flags); - - /* Also, reserve all pages that have been marked by - * stram_alloc() (e.g. for the screen memory). (This may - * treat the first ST-Ram page a second time, but that - * doesn't hurt...) */ - - rsvd_stram_end += PAGE_SIZE - 1; - rsvd_stram_end &= PAGE_MASK; - rsvd_stram_beg &= PAGE_MASK; - for( adr = rsvd_stram_beg; adr < rsvd_stram_end; adr += PAGE_SIZE ) - set_bit(PG_reserved, &mem_map[MAP_NR(adr)].flags); - } - } - + if (MACH_IS_ATARI) + atari_stram_reserve_pages( start_mem ); #endif for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) { diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c --- v2.1.86/linux/arch/m68k/mm/kmap.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mm/kmap.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,564 @@ +/* + * linux/arch/m68k/mm/kmap.c + * + * Copyright (C) 1997 Roman Hodek + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +extern pte_t *kernel_page_table (unsigned long *memavailp); + +/* Virtual address region for use by kernel_map() */ +#define KMAP_START 0xd0000000 +#define KMAP_END 0xf0000000 + +/* Granularity of kernel_map() allocations */ +#define KMAP_STEP (256*1024) + +/* Size of pool of KMAP structures; that is needed, because kernel_map() can + * be called at times where kmalloc() isn't initialized yet. */ +#define KMAP_POOL_SIZE 16 + +/* structure for maintainance of kmap regions */ +typedef struct kmap { + struct kmap *next, *prev; /* linking of list */ + unsigned long addr; /* start address of region */ + unsigned long mapaddr; /* address returned to user */ + unsigned long size; /* size of region */ + unsigned free : 1; /* flag whether free or allocated */ + unsigned kmalloced : 1; /* flag whether got this from kmalloc() */ + unsigned pool_alloc : 1; /* flag whether got this is alloced in pool */ +} KMAP; + +KMAP kmap_pool[KMAP_POOL_SIZE] = { + { NULL, NULL, KMAP_START, KMAP_START, KMAP_END-KMAP_START, 1, 0, 1 }, + { NULL, NULL, 0, 0, 0, 0, 0, 0 }, +}; + +/* + * anchor of kmap region list + * + * The list is always ordered by addresses, and regions are always adjacent, + * i.e. there must be no holes between them! + */ +KMAP *kmap_regions = &kmap_pool[0]; + +/* for protecting the kmap_regions list against races */ +static struct semaphore kmap_sem = MUTEX; + + + +/* + * Low-level allocation and freeing of KMAP structures + */ +static KMAP *alloc_kmap( int use_kmalloc ) +{ + KMAP *p; + int i; + + /* first try to get from the pool if possible */ + for( i = 0; i < KMAP_POOL_SIZE; ++i ) { + if (!kmap_pool[i].pool_alloc) { + kmap_pool[i].kmalloced = 0; + kmap_pool[i].pool_alloc = 1; + return( &kmap_pool[i] ); + } + } + + if (use_kmalloc && (p = (KMAP *)kmalloc( sizeof(KMAP), GFP_KERNEL ))) { + p->kmalloced = 1; + return( p ); + } + + return( NULL ); +} + +static void free_kmap( KMAP *p ) +{ + if (p->kmalloced) + kfree( p ); + else + p->pool_alloc = 0; +} + + +/* + * Get a free region from the kmap address range + */ +static KMAP *kmap_get_region( unsigned long size, int use_kmalloc ) +{ + KMAP *p, *q; + + /* look for a suitable free region */ + for( p = kmap_regions; p; p = p->next ) + if (p->free && p->size >= size) + break; + if (!p) { + printk( KERN_ERR "kernel_map: address space for " + "allocations exhausted\n" ); + return( NULL ); + } + + if (p->size > size) { + /* if free region is bigger than we need, split off the rear free part + * into a new region */ + if (!(q = alloc_kmap( use_kmalloc ))) { + printk( KERN_ERR "kernel_map: out of memory\n" ); + return( NULL ); + } + q->addr = p->addr + size; + q->size = p->size - size; + p->size = size; + q->free = 1; + + q->prev = p; + q->next = p->next; + p->next = q; + if (q->next) q->next->prev = q; + } + + p->free = 0; + return( p ); +} + + +/* + * Free a kernel_map region again + */ +static void kmap_put_region( KMAP *p ) +{ + KMAP *q; + + p->free = 1; + + /* merge with previous region if possible */ + q = p->prev; + if (q && q->free) { + if (q->addr + q->size != p->addr) { + printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" ); + return; + } + q->size += p->size; + q->next = p->next; + if (p->next) p->next->prev = q; + free_kmap( p ); + p = q; + } + + /* merge with following region if possible */ + q = p->next; + if (q && q->free) { + if (p->addr + p->size != q->addr) { + printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" ); + return; + } + p->size += q->size; + p->next = q->next; + if (q->next) q->next->prev = p; + free_kmap( q ); + } +} + + +/* + * kernel_map() helpers + */ +static inline pte_t * +pte_alloc_kernel_map(pmd_t *pmd, unsigned long address, + unsigned long *memavailp) +{ + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + if (pmd_none(*pmd)) { + pte_t *page = kernel_page_table(memavailp); + if (pmd_none(*pmd)) { + if (page) { + pmd_set(pmd, page); + memset( page, 0, PAGE_SIZE ); + return page + address; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + if (memavailp) + panic("kernel_map: slept during init?!?"); + cache_page((unsigned long) page); + free_page((unsigned long) page); + } + if (pmd_bad(*pmd)) { + printk( KERN_ERR "Bad pmd in pte_alloc_kernel_map: %08lx\n", + pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + address; +} + +static inline void +kernel_map_pte(pte_t *pte, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t prot) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_val(*pte) = phys_addr + pgprot_val(prot); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int +kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t prot, + unsigned long *memavailp) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + + if (CPU_IS_040_OR_060) { + do { + pte_t *pte = pte_alloc_kernel_map(pmd, address, memavailp); + if (!pte) + return -ENOMEM; + kernel_map_pte(pte, address, end - address, + address + phys_addr, prot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + } else { + /* On the 68030 we use early termination page descriptors. + Each one points to 64 pages (256K). */ + int i = (address >> (PMD_SHIFT-4)) & 15; + do { + (&pmd_val(*pmd))[i++] = (address + phys_addr) | pgprot_val(prot); + address += PMD_SIZE / 16; + } while (address < end); + } + return 0; +} + + +/* + * Map some physical address range into the kernel address space. The + * code is copied and adapted from map_chunk(). + */ +/* Rewritten by Andreas Schwab to remove all races. */ + +unsigned long kernel_map(unsigned long phys_addr, unsigned long size, + int cacheflag, unsigned long *memavailp) +{ + unsigned long retaddr, from, end; + pgd_t *dir; + pgprot_t prot; + KMAP *kmap; + + /* Round down 'phys_addr' to 256 KB and adjust size */ + retaddr = phys_addr & (KMAP_STEP-1); + size += retaddr; + phys_addr &= ~(KMAP_STEP-1); + /* Round up the size to 256 KB. It doesn't hurt if too much is + mapped... */ + size = (size + KMAP_STEP - 1) & ~(KMAP_STEP-1); + + down( &kmap_sem ); + if (!(kmap = kmap_get_region( size, memavailp == NULL ))) + return( 0 ); + from = kmap->addr; + retaddr += from; + kmap->mapaddr = retaddr; + end = from + size; + up( &kmap_sem ); + + if (CPU_IS_040_OR_060) { + pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_GLOBAL040 | + _PAGE_ACCESSED | _PAGE_DIRTY); + switch (cacheflag) { + case KERNELMAP_FULL_CACHING: + pgprot_val(prot) |= _PAGE_CACHE040; + break; + case KERNELMAP_NOCACHE_SER: + default: + pgprot_val(prot) |= _PAGE_NOCACHE_S; + break; + case KERNELMAP_NOCACHE_NONSER: + pgprot_val(prot) |= _PAGE_NOCACHE; + break; + case KERNELMAP_NO_COPYBACK: + pgprot_val(prot) |= _PAGE_CACHE040W; + break; + } + } else + pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_ACCESSED | + _PAGE_DIRTY | + ((cacheflag == KERNELMAP_FULL_CACHING || + cacheflag == KERNELMAP_NO_COPYBACK) + ? 0 : _PAGE_NOCACHE030)); + + phys_addr -= from; + dir = pgd_offset_k(from); + while (from < end) { + pmd_t *pmd = pmd_alloc_kernel(dir, from); + + if (kernel_map_pmd(pmd, from, end - from, phys_addr + from, + prot, memavailp)) { + printk( KERN_ERR "kernel_map: out of memory\n" ); + return 0UL; + } + from = (from + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + + return retaddr; +} + + +/* + * kernel_unmap() helpers + */ +static inline void pte_free_kernel_unmap( pmd_t *pmd ) +{ + unsigned long page = pmd_page(*pmd); + mem_map_t *pagemap = &mem_map[MAP_NR(page)]; + + pmd_clear(pmd); + cache_page(page); + + if (PageReserved( pagemap )) { + /* need to unreserve pages that were allocated with memavailp != NULL; + * this works only if 'page' is page-aligned */ + if (page & ~PAGE_MASK) + return; + clear_bit( PG_reserved, &pagemap->flags ); + atomic_set( &pagemap->count, 1 ); + } + free_page( page ); +} + +/* + * This not only unmaps the requested region, but also loops over the whole + * pmd to determine whether the other pte's are clear (so that the page can be + * freed.) If so, it returns 1, 0 otherwise. + */ +static inline int +kernel_unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size) +{ + pte_t *pte; + unsigned long addr2, end, end2; + int all_clear = 1; + + if (pmd_none(*pmd)) + return( 0 ); + if (pmd_bad(*pmd)) { + printk( KERN_ERR "kernel_unmap_pte_range: bad pmd (%08lx)\n", + pmd_val(*pmd) ); + pmd_clear(pmd); + return( 0 ); + } + address &= ~PMD_MASK; + addr2 = 0; + pte = pte_offset(pmd, addr2); + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + end2 = addr2 + PMD_SIZE; + while( addr2 < end2 ) { + if (!pte_none(*pte)) { + if (address <= addr2 && addr2 < end) + pte_clear(pte); + else + all_clear = 0; + } + ++pte; + addr2 += PAGE_SIZE; + } + return( all_clear ); +} + +static inline void +kernel_unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + if (pgd_bad(*dir)) { + printk( KERN_ERR "kernel_unmap_pmd_range: bad pgd (%08lx)\n", + pgd_val(*dir) ); + pgd_clear(dir); + return; + } + pmd = pmd_offset(dir, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + if (CPU_IS_040_OR_060) { + do { + if (kernel_unmap_pte_range(pmd, address, end - address)) + pte_free_kernel_unmap( pmd ); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + } else { + /* On the 68030 clear the early termination descriptors */ + int i = (address >> (PMD_SHIFT-4)) & 15; + do { + (&pmd_val(*pmd))[i++] = 0; + address += PMD_SIZE / 16; + } while (address < end); + } +} + +/* + * Unmap a kernel_map()ed region again + */ +void kernel_unmap( unsigned long addr ) +{ + unsigned long end; + pgd_t *dir; + KMAP *p; + + down( &kmap_sem ); + + /* find region for 'addr' in list; must search for mapaddr! */ + for( p = kmap_regions; p; p = p->next ) + if (!p->free && p->mapaddr == addr) + break; + if (!p) { + printk( KERN_ERR "kernel_unmap: trying to free invalid region\n" ); + return; + } + addr = p->addr; + end = addr + p->size; + kmap_put_region( p ); + + dir = pgd_offset_k( addr ); + while( addr < end ) { + kernel_unmap_pmd_range( dir, addr, end - addr ); + addr = (addr + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + + up( &kmap_sem ); + /* flushing for a range would do, but there's no such function for kernel + * address space... */ + flush_tlb_all(); +} + + +/* + * kernel_set_cachemode() helpers + */ +static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, + unsigned long size, unsigned cmode ) +{ pte_t *pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + + pte = pte_offset( pmd, address ); + address &= ~PMD_MASK; + end = address + size; + if (end >= PMD_SIZE) + end = PMD_SIZE; + + for( ; address < end; pte++ ) { + pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; + address += PAGE_SIZE; + } +} + + +static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, + unsigned long size, unsigned cmode ) +{ + pmd_t *pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + + pmd = pmd_offset( dir, address ); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { + /* 68030 early termination descriptor */ + pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; + return; + } + else { + /* "normal" tables */ + for( ; address < end; pmd++ ) { + set_cmode_pte( pmd, address, end - address, cmode ); + address = (address + PMD_SIZE) & PMD_MASK; + } + } +} + + +/* + * Set new cache mode for some kernel address space. + * The caller must push data for that range itself, if such data may already + * be in the cache. + */ +void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned cmode ) +{ + pgd_t *dir = pgd_offset_k( address ); + unsigned long end = address + size; + + if (CPU_IS_040_OR_060) { + switch( cmode ) { + case KERNELMAP_FULL_CACHING: + cmode = _PAGE_CACHE040; + break; + case KERNELMAP_NOCACHE_SER: + default: + cmode = _PAGE_NOCACHE_S; + break; + case KERNELMAP_NOCACHE_NONSER: + cmode = _PAGE_NOCACHE; + break; + case KERNELMAP_NO_COPYBACK: + cmode = _PAGE_CACHE040W; + break; + } + } else + cmode = ((cmode == KERNELMAP_FULL_CACHING || + cmode == KERNELMAP_NO_COPYBACK) ? + 0 : _PAGE_NOCACHE030); + + for( ; address < end; dir++ ) { + set_cmode_pmd( dir, address, end - address, cmode ); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + } + /* flushing for a range would do, but there's no such function for kernel + * address space... */ + flush_tlb_all(); +} diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.1.86/linux/arch/m68k/mm/memory.c Mon Jul 7 08:18:53 1997 +++ linux/arch/m68k/mm/memory.c Thu Feb 12 16:30:13 1998 @@ -18,8 +18,6 @@ #include #include -extern pte_t *kernel_page_table (unsigned long *memavailp); - /* Strings for `extern inline' functions in . If put directly into these functions, they are output for every file that includes pgtable.h */ @@ -349,10 +347,10 @@ /* no match, too, so get the actual physical address from the MMU. */ if (CPU_IS_060) { - unsigned long fs = get_fs(); + mm_segment_t fs = get_fs(); unsigned long paddr; - set_fs (SUPER_DATA); + set_fs (MAKE_MM_SEG(SUPER_DATA)); /* The PLPAR instruction causes an access error if the translation * is not possible. We don't catch that here, so a bad kernel trap @@ -368,9 +366,9 @@ } else if (CPU_IS_040) { unsigned long mmusr; - unsigned long fs = get_fs(); + mm_segment_t fs = get_fs(); - set_fs (SUPER_DATA); + set_fs (MAKE_MM_SEG(SUPER_DATA)); asm volatile (".chip 68040\n\t" "ptestr (%1)\n\t" @@ -380,6 +378,9 @@ : "a" (vaddr)); set_fs (fs); + if (mmusr & MMU_T_040) { + return (vaddr); /* Transparent translation */ + } if (mmusr & MMU_R_040) return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)); @@ -452,7 +453,7 @@ /* * if on an amiga and address is in first 16M, move it - * to the ZTWO_ADDR range + * to the ZTWO_VADDR range */ if (MACH_IS_AMIGA && paddr < 16*1024*1024) return ZTWO_VADDR(paddr); @@ -495,33 +496,6 @@ if (CPU_IS_060) cleari040(paddr); \ } while(0) -/* push page defined by virtual address in both caches */ -#define pushv040(vaddr) \ - do { unsigned long _tmp1, _tmp2; \ - __asm__ __volatile__ ("nop\n\t" \ - ".chip 68040\n\t" \ - "ptestr (%2)\n\t" \ - "movec %%mmusr,%0\n\t" \ - "andw #0xf000,%0\n\t" \ - "movel %0,%1\n\t" \ - "nop\n\t" \ - "cpushp %%bc,(%1)\n\t" \ - ".chip 68k" \ - : "=d" (_tmp1), "=a" (_tmp2) \ - : "a" (vaddr)); \ - } while (0) - -/* push page defined by virtual address in both caches */ -#define pushv060(vaddr) \ - do { unsigned long _tmp; \ - __asm__ __volatile__ (".chip 68060\n\t" \ - "plpar (%0)\n\t" \ - "cpushp %%bc,(%0)\n\t" \ - ".chip 68k" \ - : "=a" (_tmp) \ - : "0" (vaddr)); \ - } while (0) - /* * 040: Hit every page containing an address in the range paddr..paddr+len-1. @@ -632,64 +606,11 @@ } -/* - * cache_push_v() semantics: Write back any dirty cache data in the given - * area, and invalidate those entries at least in the instruction cache. This - * is intended to be used after data has been written that can be executed as - * code later. The range is defined by a _user_mode_ _virtual_ address (or, - * more exactly, the space is defined by the %sfc/%dfc register.) - */ - -void cache_push_v (unsigned long vaddr, int len) -{ - if (CPU_IS_040) { - int tmp = PAGE_SIZE; - - /* on 68040, push cache lines for pages in the range */ - len += vaddr & (PAGE_SIZE - 1); - - /* - * Work around bug I17 in the 68060 affecting some instruction - * lines not being invalidated properly. - */ - vaddr &= PAGE_MASK; - - do { - pushv040(vaddr); - vaddr += tmp; - } while ((len -= tmp) > 0); - } - else if (CPU_IS_060) { - int tmp = PAGE_SIZE; - - /* on 68040, push cache lines for pages in the range */ - len += vaddr & (PAGE_SIZE - 1); - do { - pushv060(vaddr); - vaddr += tmp; - } while ((len -= tmp) > 0); - } - /* 68030/68020 have no writeback cache; still need to clear icache. */ - else /* 68030 or 68020 */ - asm volatile ("movec %/cacr,%/d0\n\t" - "oriw %0,%/d0\n\t" - "movec %/d0,%/cacr" - : : "i" (FLUSH_I) - : "d0"); -} - #undef clear040 #undef cleari040 #undef push040 #undef pushcl040 #undef pushcli040 -#undef pushv040 -#undef pushv060 - -unsigned long mm_phys_to_virt (unsigned long addr) -{ - return PTOV (addr); -} int mm_end_of_chunk (unsigned long addr, int len) { @@ -700,227 +621,4 @@ return 1; return 0; } - -/* Map some physical address range into the kernel address space. The - * code is copied and adapted from map_chunk(). - */ - -unsigned long kernel_map(unsigned long paddr, unsigned long size, - int nocacheflag, unsigned long *memavailp ) -{ -#define STEP_SIZE (256*1024) - - static unsigned long vaddr = 0xe0000000; /* safe place */ - unsigned long physaddr, retaddr; - pte_t *ktablep = NULL; - pmd_t *kpointerp; - pgd_t *page_dir; - int pindex; /* index into pointer table */ - int prot; - - /* Round down 'paddr' to 256 KB and adjust size */ - physaddr = paddr & ~(STEP_SIZE-1); - size += paddr - physaddr; - retaddr = vaddr + (paddr - physaddr); - paddr = physaddr; - /* Round up the size to 256 KB. It doesn't hurt if too much is - * mapped... */ - size = (size + STEP_SIZE - 1) & ~(STEP_SIZE-1); - - if (CPU_IS_040_OR_060) { - prot = _PAGE_PRESENT | _PAGE_GLOBAL040; - switch( nocacheflag ) { - case KERNELMAP_FULL_CACHING: - prot |= _PAGE_CACHE040; - break; - case KERNELMAP_NOCACHE_SER: - default: - prot |= _PAGE_NOCACHE_S; - break; - case KERNELMAP_NOCACHE_NONSER: - prot |= _PAGE_NOCACHE; - break; - case KERNELMAP_NO_COPYBACK: - prot |= _PAGE_CACHE040W; - /* prot |= 0; */ - break; - } - } else - prot = _PAGE_PRESENT | - ((nocacheflag == KERNELMAP_FULL_CACHING || - nocacheflag == KERNELMAP_NO_COPYBACK) ? 0 : _PAGE_NOCACHE030); - - page_dir = pgd_offset_k(vaddr); - if (pgd_present(*page_dir)) { - kpointerp = (pmd_t *)pgd_page(*page_dir); - pindex = (vaddr >> 18) & 0x7f; - if (pindex != 0 && CPU_IS_040_OR_060) { - if (pmd_present(*kpointerp)) - ktablep = (pte_t *)pmd_page(*kpointerp); - else { - ktablep = kernel_page_table (memavailp); - /* Make entries invalid */ - memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); - pmd_set(kpointerp,ktablep); - } - ktablep += (pindex & 15)*64; - } - } - else { - /* we need a new pointer table */ - kpointerp = get_kpointer_table (); - pgd_set(page_dir, (pmd_t *)kpointerp); - memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); - pindex = 0; - } - - for (physaddr = paddr; physaddr < paddr + size; vaddr += STEP_SIZE) { - - if (pindex > 127) { - /* we need a new pointer table */ - kpointerp = get_kpointer_table (); - pgd_set(pgd_offset_k(vaddr), (pmd_t *)kpointerp); - memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); - pindex = 0; - } - - if (CPU_IS_040_OR_060) { - int i; - unsigned long ktable; - - /* - * 68040, use page tables pointed to by the - * kernel pointer table. - */ - - if ((pindex & 15) == 0) { - /* Need new page table every 4M on the '040 */ - ktablep = kernel_page_table (memavailp); - /* Make entries invalid */ - memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); - } - - ktable = VTOP(ktablep); - - /* - * initialize section of the page table mapping - * this 1M portion. - */ - for (i = 0; i < 64; i++) { - pte_val(*ktablep++) = physaddr | prot; - physaddr += PAGE_SIZE; - } - - /* - * make the kernel pointer table point to the - * kernel page table. - */ - - ((unsigned long *)kpointerp)[pindex++] = ktable | _PAGE_TABLE; - - } else { - /* - * 68030, use early termination page descriptors. - * Each one points to 64 pages (256K). - */ - ((unsigned long *)kpointerp)[pindex++] = physaddr | prot; - physaddr += 64 * PAGE_SIZE; - } - } - - return( retaddr ); -} - - -static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, - unsigned long size, unsigned cmode ) -{ pte_t *pte; - unsigned long end; - - if (pmd_none(*pmd)) - return; - - pte = pte_offset( pmd, address ); - address &= ~PMD_MASK; - end = address + size; - if (end >= PMD_SIZE) - end = PMD_SIZE; - - for( ; address < end; pte++ ) { - pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; - address += PAGE_SIZE; - } -} - - -static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, - unsigned long size, unsigned cmode ) -{ - pmd_t *pmd; - unsigned long end; - - if (pgd_none(*dir)) - return; - - pmd = pmd_offset( dir, address ); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - - if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { - /* 68030 early termination descriptor */ - pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; - return; - } - else { - /* "normal" tables */ - for( ; address < end; pmd++ ) { - set_cmode_pte( pmd, address, end - address, cmode ); - address = (address + PMD_SIZE) & PMD_MASK; - } - } -} - - -/* - * Set new cache mode for some kernel address space. - * The caller must push data for that range itself, if such data may already - * be in the cache. - */ - -void kernel_set_cachemode( unsigned long address, unsigned long size, - unsigned cmode ) -{ - pgd_t *dir = pgd_offset_k( address ); - unsigned long end = address + size; - - if (CPU_IS_040_OR_060) { - switch( cmode ) { - case KERNELMAP_FULL_CACHING: - cmode = _PAGE_CACHE040; - break; - case KERNELMAP_NOCACHE_SER: - default: - cmode = _PAGE_NOCACHE_S; - break; - case KERNELMAP_NOCACHE_NONSER: - cmode = _PAGE_NOCACHE; - break; - case KERNELMAP_NO_COPYBACK: - cmode = _PAGE_CACHE040W; - break; - } - } else - cmode = ((cmode == KERNELMAP_FULL_CACHING || - cmode == KERNELMAP_NO_COPYBACK) ? - 0 : _PAGE_NOCACHE030); - - for( ; address < end; dir++ ) { - set_cmode_pmd( dir, address, end - address, cmode ); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - } - flush_tlb_all(); -} - diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mvme16x/16xints.c linux/arch/m68k/mvme16x/16xints.c --- v2.1.86/linux/arch/m68k/mvme16x/16xints.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mvme16x/16xints.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,144 @@ +/* + * arch/m68k/mvme16x/16xints.c + * + * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk] + * + * based on amiints.c -- Amiga Linux interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp); + +/* + * This should ideally be 4 elements only, for speed. + */ + +static struct { + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; + unsigned count; +} irq_tab[192]; + +/* + * void mvme16x_init_IRQ (void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function is called during kernel startup to initialize + * the mvme16x IRQ handling routines. Should probably ensure + * that the base vectors for the VMEChip2 and PCCChip2 are valid. + */ + +void mvme16x_init_IRQ (void) +{ + int i; + + for (i = 0; i < 192; i++) { + irq_tab[i].handler = mvme16x_defhand; + irq_tab[i].flags = IRQ_FLG_STD; + irq_tab[i].dev_id = NULL; + irq_tab[i].devname = NULL; + irq_tab[i].count = 0; + } +} + +int mvme16x_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq < 64 || irq > 255) { + printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + if (!(irq_tab[irq-64].flags & IRQ_FLG_STD)) { + if (irq_tab[irq-64].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_tab[irq-64].devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_tab[irq-64].devname); + return -EBUSY; + } + } + irq_tab[irq-64].handler = handler; + irq_tab[irq-64].flags = flags; + irq_tab[irq-64].dev_id = dev_id; + irq_tab[irq-64].devname = devname; + return 0; +} + +void mvme16x_free_irq(unsigned int irq, void *dev_id) +{ + if (irq < 64 || irq > 255) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_tab[irq-64].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_tab[irq-64].devname); + + irq_tab[irq-64].handler = mvme16x_defhand;; + irq_tab[irq-64].flags = IRQ_FLG_STD; + irq_tab[irq-64].dev_id = NULL; + irq_tab[irq-64].devname = NULL; +} + +void mvme16x_process_int (unsigned long vec, struct pt_regs *fp) +{ + if (vec < 64 || vec > 255) + panic ("mvme16x_process_int: Illegal vector %ld", vec); + irq_tab[vec-64].count++; + irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp); +} + +int mvme16x_get_irq_list (char *buf) +{ + int i, len = 0; + + for (i = 0; i < 192; i++) { + if (irq_tab[i].count) + len += sprintf (buf+len, "Vec 0x%02x: %8d %s\n", + i+64, irq_tab[i].count, + irq_tab[i].devname ? irq_tab[i].devname : "free"); + } + return len; +} + + +static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp) +{ + panic ("Unknown interrupt 0x%02x", irq); +} + + +void mvme16x_enable_irq (unsigned int irq) +{ +} + + +void mvme16x_disable_irq (unsigned int irq) +{ +} + + diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mvme16x/Makefile linux/arch/m68k/mvme16x/Makefile --- v2.1.86/linux/arch/m68k/mvme16x/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mvme16x/Makefile Thu Feb 12 16:30:13 1998 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/mvme16x 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... + +O_TARGET := mvme16x.o +O_OBJS := config.o 16xints.o +#OX_OBJS = ksyms.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c --- v2.1.86/linux/arch/m68k/mvme16x/config.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mvme16x/config.c Thu Feb 12 16:30:13 1998 @@ -0,0 +1,403 @@ +/* + * arch/m68k/mvme16x/config.c + * + * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk] + * + * Based on: + * + * linux/amiga/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal 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 + +typedef struct { + unsigned char + ctrl, + bcd_sec, + bcd_min, + bcd_hr, + bcd_dow, + bcd_dom, + bcd_mth, + bcd_year; +} MK48T08; + +#define RTC_WRITE 0x80 +#define RTC_READ 0x40 +#define RTC_STOP 0x20 + +int atari_SCC_reset_done = 1; /* So SCC doesn't get reset */ +u_long atari_mch_cookie = 0; + +MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8; + +extern void mvme16x_process_int (int level, struct pt_regs *regs); +extern void mvme16x_init_IRQ (void); +extern void mvme16x_free_irq (unsigned int, void *); +extern int mvme16x_get_irq_list (char *); +extern void mvme16x_enable_irq (unsigned int); +extern void mvme16x_disable_irq (unsigned int); +static void mvme16x_get_model(char *model); +static int mvme16x_get_hardware_list(char *buffer); +extern int mvme16x_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); +extern void mvme16x_sched_init(void (*handler)(int, void *, struct pt_regs *)); +extern int mvme16x_keyb_init(void); +extern int mvme16x_kbdrate (struct kbd_repeat *); +extern unsigned long mvme16x_gettimeoffset (void); +extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec); +extern int mvme16x_hwclk (int, struct hwclk_time *); +extern int mvme16x_set_clock_mmss (unsigned long); +extern void mvme16x_check_partition (struct gendisk *hd, unsigned int dev); +extern void mvme16x_mksound( unsigned int count, unsigned int ticks ); +extern void mvme16x_reset (void); +extern void mvme16x_waitbut(void); + +int bcd2int (unsigned char b); + +/* Save tick handler routine pointer, will point to do_timer() in + * kernel/sched.c, called via mvme16x_process_int() */ + +static void (*tick_handler)(int, void *, struct pt_regs *); + + +unsigned short mvme16x_config; + + +int mvme16x_kbdrate (struct kbd_repeat *k) +{ + return 0; +} + +void mvme16x_mksound( unsigned int count, unsigned int ticks ) +{ +} + +void mvme16x_reset() +{ + printk ("\r\n\nCalled mvme16x_reset\r\n" + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"); + /* The string of returns is to delay the reset until the whole + * message is output. Assert reset bit in GCSR */ + *(volatile char *)0xfff40107 = 0x80; +} + +static void mvme16x_get_model(char *model) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + char suf[4]; + + suf[1] = p->brdsuffix[0]; + suf[2] = p->brdsuffix[1]; + suf[3] = '\0'; + suf[0] = suf[1] ? '-' : '\0'; + + sprintf(model, "Motorola MVME%x%s", p->brdno, suf); +} + + +static int mvme16x_get_hardware_list(char *buffer) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + int len = 0; + + if (p->brdno == 0x0162 || p->brdno == 0x0172) + { + unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; + + len += sprintf (buffer+len, "VMEchip2 %spresent\n", + rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); + len += sprintf (buffer+len, "SCSI interface %spresent\n", + rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); + len += sprintf (buffer+len, "Ethernet i/f %spresent\n", + rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); + } + else + *buffer = '\0'; + + return (len); +} + + +__initfunc(void config_mvme16x(void)) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + char id[40]; + + mach_sched_init = mvme16x_sched_init; + mach_keyb_init = mvme16x_keyb_init; + mach_kbdrate = mvme16x_kbdrate; + mach_init_IRQ = mvme16x_init_IRQ; + mach_gettimeoffset = mvme16x_gettimeoffset; + mach_gettod = mvme16x_gettod; + mach_hwclk = mvme16x_hwclk; + mach_set_clock_mmss = mvme16x_set_clock_mmss; +/* kd_mksound = mvme16x_mksound; */ + mach_reset = mvme16x_reset; + mach_free_irq = mvme16x_free_irq; + mach_process_int = mvme16x_process_int; + mach_get_irq_list = mvme16x_get_irq_list; + mach_request_irq = mvme16x_request_irq; + enable_irq = mvme16x_enable_irq; + disable_irq = mvme16x_disable_irq; + mach_get_model = mvme16x_get_model; + mach_get_hardware_list = mvme16x_get_hardware_list; + + /* Report board revision */ + + if (strncmp("BDID", p->bdid, 4)) + { + printk ("\n\nBug call .BRD_ID returned garbage - giving up\n\n"); + while (1) + ; + } + mvme16x_get_model(id); + printk ("\nBRD_ID: %s BUG %x.%x %02x/%02x/%02x\n", id, p->rev>>4, + p->rev&0xf, p->yr, p->mth, p->day); + if (p->brdno == 0x0162 || p->brdno == 0x172) + { + unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; + + mvme16x_config = rev | MVME16x_CONFIG_GOT_SCCA; + + printk ("MVME%x Hardware status:\n", p->brdno); + printk (" CPU Type 68%s040\n", + rev & MVME16x_CONFIG_GOT_FPU ? "" : "LC"); + printk (" CPU clock %dMHz\n", + rev & MVME16x_CONFIG_SPEED_32 ? 32 : 25); + printk (" VMEchip2 %spresent\n", + rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); + printk (" SCSI interface %spresent\n", + rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); + printk (" Ethernet interface %spresent\n", + rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); + } + else + mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401; +} + +static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp) +{ + *(volatile unsigned char *)0xfff4201b |= 8; + tick_handler(irq, dev_id, fp); +} + +void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) +{ + tick_handler = timer_routine; + /* Using PCCchip2 or MC2 chip tick timer 1 */ + *(volatile unsigned long *)0xfff42008 = 0; + *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ + *(volatile unsigned char *)0xfff42017 |= 3; + *(volatile unsigned char *)0xfff4201b = 0x16; + if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0, + "timer", mvme16x_timer_int)) + panic ("Couldn't register timer int"); +} + + +/* This is always executed with interrupts disabled. */ +unsigned long mvme16x_gettimeoffset (void) +{ + return (*(volatile unsigned long *)0xfff42008); +} + +extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ + rtc->ctrl = RTC_READ; + *year = bcd2int (rtc->bcd_year); + *mon = bcd2int (rtc->bcd_mth); + *day = bcd2int (rtc->bcd_dom); + *hour = bcd2int (rtc->bcd_hr); + *min = bcd2int (rtc->bcd_min); + *sec = bcd2int (rtc->bcd_sec); + rtc->ctrl = 0; +} + +int bcd2int (unsigned char b) +{ + return ((b>>4)*10 + (b&15)); +} + +int mvme16x_hwclk(int op, struct hwclk_time *t) +{ + return 0; +} + +int mvme16x_set_clock_mmss (unsigned long nowtime) +{ + return 0; +} + +/* + * console_map_init(), here to avoid having to modify drivers/block/genhd.c + */ + +void console_map_init(void) +{ +} + +/* + * fbmem_init(), here to avoid having to modify drivers/char/mem.c + */ + +void fbmem_init(void) +{ +} + +/* Avoid mods to drivers/char/tty_io.c */ + +unsigned long con_init(unsigned long kmem_start) +{ + return (kmem_start); +} + +/* Avoid mods to drivers/char/tty_io.c */ + +int vcs_init(void) +{ + return (0); +} + +/* Avoid mods to drivers/char/tty_io.c */ + +int kbd_init(void) +{ + return (0); +} + +/* Avoid mods to init/main.c */ + +void no_scroll(char *str, int *ints) +{ +} + +/* Avoid mods to kernel/panic.c */ + +void do_unblank_screen(void) +{ +} + +int mvme16x_keyb_init (void) +{ + return 0; +} + +void mvme16x_set_vectors (void) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + unsigned long *new = (unsigned long *)vectors; + unsigned long *old = (unsigned long *)0xffe00000;; + + *(new+4) = *(old+4); /* Illegal instruction */ + *(new+9) = *(old+9); /* Trace */ + *(new+47) = *(old+47); /* Trap #15 */ + + if (p->brdno == 0x0162 || p->brdno == 0x172) + *(new+0x5e) = *(old+0x5e); /* ABORT switch */ + else + *(new+0x6e) = *(old+0x6e); /* ABORT switch */ +} + +/*------------------- Serial console stuff ------------------------*/ + +extern void mvme167_serial_console_setup(int cflag); +extern void serial167_write(struct console *co, const char *str, unsigned cnt); +extern void vme_scc_write(struct console *co, const char *str, unsigned cnt); + + +void mvme16x_init_console_port (struct console *co, int cflag) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + + switch (p->brdno) + { +#ifdef CONFIG_MVME162_SCC + case 0x0162: + case 0x0172: + co->write = vme_scc_write; + return; +#endif +#ifdef CONFIG_SERIAL167 + case 0x0166: + case 0x0167: + case 0x0176: + case 0x0177: + co->write = serial167_write; + mvme167_serial_console_setup (cflag); + return; +#endif + default: + panic ("No console support for MVME%x\n", p->brdno); + } + return; +} + + +#ifdef CONFIG_MVME162_SCC + +static void scc_delay (void) +{ + int n; + char i; + + for (n = 0; n < 20; n++) + i = *(volatile char *)0; +} + +static void scc_write (char ch) +{ + volatile char *p = (volatile char *)SCC_A_ADDR; + + do { + scc_delay(); + } + while (!(*p & 4)); + scc_delay(); + *p = 8; + scc_delay(); + *p = ch; +} + + +void vme_scc_write (struct console *co, const char *str, unsigned count) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + while (count--) + { + if (*str == '\n') + scc_write ('\r'); + scc_write (*str++); + } + restore_flags(flags); +} +#endif diff -u --recursive --new-file v2.1.86/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds --- v2.1.86/linux/arch/m68k/vmlinux.lds Sat May 24 09:10:22 1997 +++ linux/arch/m68k/vmlinux.lds Thu Feb 12 16:30:13 1998 @@ -31,8 +31,7 @@ CONSTRUCTORS } - . = ALIGN(8192); - init_task : { *(init_task) } /* The initial task and kernel stack */ + .bss : { *(.bss) } /* BSS */ _edata = .; /* End of data section */ @@ -40,13 +39,11 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } - . = ALIGN(4096); + . = ALIGN(8192); __init_end = .; - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } + init_task : { *(init_task) } /* The initial task and kernel stack */ + _end = . ; /* Stabs debugging sections. */ diff -u --recursive --new-file v2.1.86/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c --- v2.1.86/linux/arch/sparc/ap1000/tnet.c Thu Feb 12 20:56:04 1998 +++ linux/arch/sparc/ap1000/tnet.c Wed Feb 11 16:16:43 1998 @@ -578,7 +578,7 @@ static void free_skb(struct sk_buff *skb, int op) { - dev_kfree_skb(skb,op); + dev_kfree_skb(skb); } void tnet_send_ip(int cid,struct sk_buff *skb) diff -u --recursive --new-file v2.1.86/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.1.86/linux/drivers/block/ll_rw_blk.c Sun Dec 28 12:05:44 1997 +++ linux/drivers/block/ll_rw_blk.c Thu Feb 12 14:12:44 1998 @@ -35,6 +35,11 @@ DECLARE_TASK_QUEUE(tq_disk); /* + * Protect the request list against multiple users.. + */ +spinlock_t current_lock = SPIN_LOCK_UNLOCKED; + +/* * used to wait on when there are no free requests */ struct wait_queue * wait_for_request = NULL; diff -u --recursive --new-file v2.1.86/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.1.86/linux/drivers/char/esp.c Mon Dec 1 09:45:43 1997 +++ linux/drivers/char/esp.c Thu Feb 12 15:47:44 1998 @@ -29,9 +29,8 @@ * by Chris Faylor. * * Most recent changes: (Andrew J. Robinson) - * Added rx_trigger, tx_trigger, flow_off, flow_on, and rx_timeout options. - * ESP enhanced mode configuration can be viewed/changed by a patched - * version of setserial. + * Support for PIO mode. This allows the driver to work properly with + * multiport cards. * * This module exports the following rs232 io functions: * @@ -94,13 +93,14 @@ static char *dma_buffer; static int dma_bytes; +static struct esp_pio_buffer *free_pio_buf; #define DMA_BUFFER_SZ 1024 #define WAKEUP_CHARS 1024 static char *serial_name = "ESP serial driver"; -static char *serial_version = "1.6"; +static char *serial_version = "2.0"; static DECLARE_TASK_QUEUE(tq_esp); @@ -135,7 +135,7 @@ #define DBG_CNT(s) #endif -static struct esp_struct *IRQ_ports[16]; +static struct esp_struct *ports; static void change_speed(struct esp_struct *info); static void rs_wait_until_sent(struct tty_struct *, int); @@ -290,181 +290,249 @@ queue_task(&info->tqueue, &tq_esp); mark_bh(ESP_BH); } - -static void receive_chars_dma(struct esp_struct *info) +static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void) { - info->stat_flags &= ~(ESP_STAT_RX_TIMEOUT | ESP_STAT_NEED_DMA_RX); + struct esp_pio_buffer *buf; - serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); - serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL); - dma_bytes = serial_in(info, UART_ESI_STAT1) << 8; - dma_bytes |= serial_in(info, UART_ESI_STAT2); + if (free_pio_buf) { + buf = free_pio_buf; + free_pio_buf = buf->next; + } else { + buf = (struct esp_pio_buffer *) + kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); + } - if (!dma_bytes) - return; - - info->stat_flags |= ESP_STAT_DMA_RX; - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma, DMA_MODE_READ); - set_dma_addr(dma, virt_to_bus(dma_buffer)); - set_dma_count(dma, dma_bytes); - enable_dma(dma); - serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); + return buf; } -static void do_ttybuf(void *private_) +static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf) { - struct esp_struct *info = (struct esp_struct *) private_; - struct tty_struct *tty; - int avail_bytes, x_bytes; - unsigned long int flags; + buf->next = free_pio_buf; + free_pio_buf = buf; +} - save_flags(flags); cli(); +static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) +{ + struct tty_struct *tty = info->tty; + int i; + struct esp_pio_buffer *pio_buf; + struct esp_pio_buffer *err_buf; + unsigned char status_mask; + + pio_buf = get_pio_buffer(); + + if (!pio_buf) + return; + + err_buf = get_pio_buffer(); + + if (!err_buf) { + release_pio_buffer(pio_buf); + return; + } + + sti(); + + status_mask = (info->read_status_mask >> 2) & 0x07; + + for (i = 0; i < num_bytes - 1; i += 2) { + *((unsigned short *)(pio_buf->data + i)) = + inw(info->port + UART_ESI_RX); + err_buf->data[i] = serial_in(info, UART_ESI_RWS); + err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask; + err_buf->data[i] &= status_mask; + } + + if (num_bytes & 0x0001) { + pio_buf->data[num_bytes - 1] = serial_in(info, UART_ESI_RX); + err_buf->data[num_bytes - 1] = + (serial_in(info, UART_ESI_RWS) >> 3) & status_mask; + } + + cli(); + + /* make sure everything is still ok since interrupts were enabled */ tty = info->tty; if (!tty) { - restore_flags(flags); + release_pio_buffer(pio_buf); + release_pio_buffer(err_buf); + info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; return; } - avail_bytes = TTY_FLIPBUF_SIZE - tty->flip.count; + status_mask = (info->ignore_status_mask >> 2) & 0x07; - if (avail_bytes) { - if (info->tty_buf->count < avail_bytes) - x_bytes = info->tty_buf->count; - else - x_bytes = avail_bytes; + for (i = 0; i < num_bytes; i++) { + if (!(err_buf->data[i] & status_mask)) { + *(tty->flip.char_buf_ptr++) = pio_buf->data[i]; - tty->flip.count += x_bytes; - memcpy(tty->flip.char_buf_ptr, info->tty_buf->char_buf, - x_bytes); - memcpy(tty->flip.flag_buf_ptr, info->tty_buf->flag_buf, - x_bytes); - tty->flip.char_buf_ptr += x_bytes; - tty->flip.flag_buf_ptr += x_bytes; - info->tty_buf->count -= x_bytes; - info->tty_buf->char_buf_ptr -= x_bytes; - info->tty_buf->flag_buf_ptr -= x_bytes; - - if (info->tty_buf->count) { - memmove(info->tty_buf->char_buf, - info->tty_buf->char_buf + x_bytes, - info->tty_buf->count); - queue_task(&info->tty_buf->tqueue, - &tq_timer); - } + if (err_buf->data[i] & 0x04) { + *(tty->flip.flag_buf_ptr++) = TTY_BREAK; - queue_task(&tty->flip.tqueue, &tq_timer); - } else { - queue_task(&info->tty_buf->tqueue, &tq_timer); + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } + else if (err_buf->data[i] & 0x02) + *(tty->flip.flag_buf_ptr++) = TTY_FRAME; + else if (err_buf->data[i] & 0x01) + *(tty->flip.flag_buf_ptr++) = TTY_PARITY; + else + *(tty->flip.flag_buf_ptr++) = 0; + + tty->flip.count++; + } } - restore_flags(flags); + queue_task(&tty->flip.tqueue, &tq_timer); + + info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; + release_pio_buffer(pio_buf); + release_pio_buffer(err_buf); +} + +static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes) +{ + info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; + dma_bytes = num_bytes; + info->stat_flags |= ESP_STAT_DMA_RX; + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma, DMA_MODE_READ); + set_dma_addr(dma, virt_to_bus(dma_buffer)); + set_dma_count(dma, dma_bytes); + enable_dma(dma); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); } static _INLINE_ void receive_chars_dma_done(struct esp_struct *info, int status) { struct tty_struct *tty = info->tty; - int num_bytes, bytes_left, x_bytes; - struct tty_flip_buffer *buffer; - - if (!(info->stat_flags & ESP_STAT_DMA_RX)) - return; + int num_bytes; disable_dma(dma); clear_dma_ff(dma); info->stat_flags &= ~ESP_STAT_DMA_RX; - bytes_left = num_bytes = dma_bytes - get_dma_residue(dma); + num_bytes = dma_bytes - get_dma_residue(dma); info->icount.rx += num_bytes; - buffer = &(tty->flip); - - if (info->tty_buf->count && (tty->flip.count < TTY_FLIPBUF_SIZE)) - do_ttybuf(info); - - while (bytes_left > 0) { - if ((buffer->count + bytes_left) > TTY_FLIPBUF_SIZE) - x_bytes = TTY_FLIPBUF_SIZE - buffer->count; - else - x_bytes = bytes_left; - memcpy(buffer->char_buf_ptr, - dma_buffer + (num_bytes - bytes_left), x_bytes); - buffer->char_buf_ptr += x_bytes; - buffer->count += x_bytes; - memset(buffer->flag_buf_ptr, 0, x_bytes); - buffer->flag_buf_ptr += x_bytes; - bytes_left -= x_bytes; - - if (bytes_left > 0) { - if (buffer == info->tty_buf) - break; - else - buffer = info->tty_buf; - } - } + memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes); + tty->flip.char_buf_ptr += num_bytes; + tty->flip.count += num_bytes; + memset(tty->flip.flag_buf_ptr, 0, num_bytes); + tty->flip.flag_buf_ptr += num_bytes; if (num_bytes > 0) { - buffer->flag_buf_ptr--; + tty->flip.flag_buf_ptr--; status &= (0x1c & info->read_status_mask); if (status & info->ignore_status_mask) { - buffer->count--; - buffer->char_buf_ptr--; - buffer->flag_buf_ptr--; + tty->flip.count--; + tty->flip.char_buf_ptr--; + tty->flip.flag_buf_ptr--; } else if (status & 0x10) { - *buffer->flag_buf_ptr = TTY_BREAK; + *tty->flip.flag_buf_ptr = TTY_BREAK; (info->icount.brk)++; if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (status & 0x08) { - *buffer->flag_buf_ptr = TTY_FRAME; + *tty->flip.flag_buf_ptr = TTY_FRAME; (info->icount.frame)++; } else if (status & 0x04) { - *buffer->flag_buf_ptr = TTY_PARITY; + *tty->flip.flag_buf_ptr = TTY_PARITY; (info->icount.parity)++; } - buffer->flag_buf_ptr++; + tty->flip.flag_buf_ptr++; - if (buffer == info->tty_buf) - queue_task(&info->tty_buf->tqueue, &tq_timer); - queue_task(&tty->flip.tqueue, &tq_timer); } if (dma_bytes != num_bytes) { + num_bytes = dma_bytes - num_bytes; dma_bytes = 0; - receive_chars_dma(info); + receive_chars_dma(info, num_bytes); } else dma_bytes = 0; } -static void transmit_chars_dma(struct esp_struct *info) +static _INLINE_ void transmit_chars_pio(struct esp_struct *info, + int space_avail) { - info->stat_flags &= ~ESP_STAT_NEED_DMA_TX; + int i; + struct esp_pio_buffer *pio_buf; - if ((info->xmit_cnt <= 0) || info->tty->stopped) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); - serial_out(info, UART_ESI_CMD2, info->IER); + pio_buf = get_pio_buffer(); + + if (!pio_buf) return; + + while (space_avail && info->xmit_cnt) { + if (info->xmit_tail + space_avail <= ESP_XMIT_SIZE) { + memcpy(pio_buf->data, + &(info->xmit_buf[info->xmit_tail]), + space_avail); + } else { + i = ESP_XMIT_SIZE - info->xmit_tail; + memcpy(pio_buf->data, + &(info->xmit_buf[info->xmit_tail]), i); + memcpy(&(pio_buf->data[i]), info->xmit_buf, + space_avail - i); + } + + info->xmit_cnt -= space_avail; + info->xmit_tail = (info->xmit_tail + space_avail) & + (ESP_XMIT_SIZE - 1); + + sti(); + + for (i = 0; i < space_avail - 1; i += 2) { + outw(*((unsigned short *)(pio_buf->data + i)), + info->port + UART_ESI_TX); + } + + if (space_avail & 0x0001) + serial_out(info, UART_ESI_TX, + pio_buf->data[space_avail - 1]); + + cli(); + + if (info->xmit_cnt) { + serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); + serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); + space_avail = serial_in(info, UART_ESI_STAT1) << 8; + space_avail |= serial_in(info, UART_ESI_STAT2); + + if (space_avail > info->xmit_cnt) + space_avail = info->xmit_cnt; + } } - - serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); - serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); - dma_bytes = serial_in(info, UART_ESI_STAT1) << 8; - dma_bytes |= serial_in(info, UART_ESI_STAT2); - if (!dma_bytes) - return; + if (info->xmit_cnt < WAKEUP_CHARS) { + rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP); - if (dma_bytes > info->xmit_cnt) - dma_bytes = info->xmit_cnt; +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_ESI_CMD1, + ESI_SET_SRV_MASK); + serial_out(info, UART_ESI_CMD2, info->IER); + } + } + + release_pio_buffer(pio_buf); +} + +static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes) +{ + dma_bytes = num_bytes; if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) { memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]), @@ -507,9 +575,6 @@ { int num_bytes; - if (!(info->stat_flags & ESP_STAT_DMA_TX)) - return; - disable_dma(dma); clear_dma_ff(dma); @@ -564,8 +629,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); + queue_task(&info->tqueue_hangup, &tq_scheduler); } } } @@ -575,92 +639,104 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - struct esp_struct * info, *stop_port = 0; + struct esp_struct * info; unsigned err_status; unsigned int scratch; - int pre_bytes; - + #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d)...", irq); #endif - - /* This routine will currently check ALL ports when an interrupt */ - /* is received from ANY port */ + info = (struct esp_struct *)dev_id; + err_status = 0; + scratch = serial_in(info, UART_ESI_SID); - info = IRQ_ports[irq]; - - if (!info) + cli(); + + if (!info->tty) { + sti(); return; + } - do { - if (!info->tty) { - info = info->next_port; - continue; - } - - pre_bytes = dma_bytes; - err_status = 0; - scratch = serial_in(info, UART_ESI_SID); - if (scratch & 0x04) { /* error - check for rx timeout */ - serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT); - err_status = serial_in(info, UART_ESI_STAT1); - serial_in(info, UART_ESI_STAT2); + if (scratch & 0x04) { /* error */ + serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT); + err_status = serial_in(info, UART_ESI_STAT1); + serial_in(info, UART_ESI_STAT2); - if (err_status & 0x01) - info->stat_flags |= ESP_STAT_RX_TIMEOUT; + if (err_status & 0x01) + info->stat_flags |= ESP_STAT_RX_TIMEOUT; - if (err_status & 0x20) /* UART status */ - check_modem_status(info); + if (err_status & 0x20) /* UART status */ + check_modem_status(info); - if (err_status & 0x80) /* Start break */ - wake_up_interruptible(&info->break_wait); - } + if (err_status & 0x80) /* Start break */ + wake_up_interruptible(&info->break_wait); + } - if ((scratch & 0x88) || /* DMA completed or timed out */ - (err_status & 0x1c) /* receive error */) { - receive_chars_dma_done(info, err_status); - transmit_chars_dma_done(info); - } + if ((scratch & 0x88) || /* DMA completed or timed out */ + (err_status & 0x1c) /* receive error */) { + if (info->stat_flags & ESP_STAT_DMA_RX) + receive_chars_dma_done(info, err_status); + else if (info->stat_flags & ESP_STAT_DMA_TX) + transmit_chars_dma_done(info); + } - if (((scratch & 0x01) || - (info->stat_flags & ESP_STAT_RX_TIMEOUT)) && - (info->IER & UART_IER_RDI)) - if (dma_bytes) - info->stat_flags |= ESP_STAT_NEED_DMA_RX; - else - receive_chars_dma(info); + if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && + ((scratch & 0x01) || (info->stat_flags & ESP_STAT_RX_TIMEOUT)) && + (info->IER & UART_IER_RDI)) { + int num_bytes; - if ((scratch & 0x02) && (info->IER & UART_IER_THRI)) - if (dma_bytes) - info->stat_flags |= ESP_STAT_NEED_DMA_TX; + serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); + serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL); + num_bytes = serial_in(info, UART_ESI_STAT1) << 8; + num_bytes |= serial_in(info, UART_ESI_STAT2); + + if (num_bytes > (TTY_FLIPBUF_SIZE - info->tty->flip.count)) + num_bytes = TTY_FLIPBUF_SIZE - info->tty->flip.count; + + if (num_bytes) { + if (dma_bytes || + (info->stat_flags & ESP_STAT_USE_PIO) || + (num_bytes <= ESP_PIO_THRESHOLD)) + receive_chars_pio(info, num_bytes); else - transmit_chars_dma(info); - - info->last_active = jiffies; - - if (pre_bytes && !dma_bytes) /* released DMA */ - stop_port = info; - - info = info->next_port; - } while ((info->irq == irq) && (info != IRQ_ports[irq])); + receive_chars_dma(info, num_bytes); + } + } + + if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && + (scratch & 0x02) && (info->IER & UART_IER_THRI)) { + if ((info->xmit_cnt <= 0) || info->tty->stopped) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); + serial_out(info, UART_ESI_CMD2, info->IER); + } else { + int num_bytes; - if (stop_port) { - while ((info != stop_port) && (!dma_bytes)) { - if (info->tty) { - if (info->stat_flags & ESP_STAT_NEED_DMA_RX) - receive_chars_dma(info); - if ((info->stat_flags & ESP_STAT_NEED_DMA_TX) - && !dma_bytes) - transmit_chars_dma(info); + serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); + serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); + num_bytes = serial_in(info, UART_ESI_STAT1) << 8; + num_bytes |= serial_in(info, UART_ESI_STAT2); + + if (num_bytes > info->xmit_cnt) + num_bytes = info->xmit_cnt; + + if (num_bytes) { + if (dma_bytes || + (info->stat_flags & ESP_STAT_USE_PIO) || + (num_bytes <= ESP_PIO_THRESHOLD)) + transmit_chars_pio(info, num_bytes); + else + transmit_chars_dma(info, num_bytes); } - - info = info->next_port; } } + info->last_active = jiffies; + #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif + sti(); } /* @@ -734,7 +810,11 @@ { /* put ESPC in enhanced mode */ serial_out(info, UART_ESI_CMD1, ESI_SET_MODE); - serial_out(info, UART_ESI_CMD2, 0x31); + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + serial_out(info, UART_ESI_CMD2, 0x01); + else + serial_out(info, UART_ESI_CMD2, 0x31); /* disable interrupts for now */ serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); @@ -742,8 +822,14 @@ /* set interrupt and DMA channel */ serial_out(info, UART_ESI_CMD1, ESI_SET_IRQ); - serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01); + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + serial_out(info, UART_ESI_CMD2, 0x01); + else + serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01); + serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); + if (info->line % 8) /* secondary port */ serial_out(info, UART_ESI_CMD2, 0x0d); /* shared */ else if (info->irq == 9) @@ -753,7 +839,12 @@ /* set error status mask (check this) */ serial_out(info, UART_ESI_CMD1, ESI_SET_ERR_MASK); - serial_out(info, UART_ESI_CMD2, 0xbd); + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + serial_out(info, UART_ESI_CMD2, 0xa1); + else + serial_out(info, UART_ESI_CMD2, 0xbd); + serial_out(info, UART_ESI_CMD2, 0x00); /* set DMA timeout */ @@ -767,9 +858,9 @@ serial_out(info, UART_ESI_CMD2, tx_trigger >> 8); serial_out(info, UART_ESI_CMD2, tx_trigger); - /* Set clock scaling */ + /* Set clock scaling and wait states */ serial_out(info, UART_ESI_CMD1, ESI_SET_PRESCALAR); - serial_out(info, UART_ESI_CMD2, ESPC_SCALE); + serial_out(info, UART_ESI_CMD2, 0x04 | ESPC_SCALE); /* set reinterrupt pacing */ serial_out(info, UART_ESI_CMD1, ESI_SET_REINTR); @@ -780,43 +871,23 @@ { unsigned long flags; int retval=0; - int next_irq; - struct esp_struct *next_info = 0; unsigned int num_chars; save_flags(flags); cli(); - if (info->flags & ASYNC_INITIALIZED) - goto errout; + if (info->flags & ASYNC_INITIALIZED) { + restore_flags(flags); + return retval; + } if (!info->xmit_buf) { info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL); if (!info->xmit_buf) { - retval = -ENOMEM; - goto errout; + restore_flags(flags); + return -ENOMEM; } } - if (!info->tty_buf) { - info->tty_buf = (struct tty_flip_buffer *)kmalloc( - sizeof(struct tty_flip_buffer), GFP_KERNEL); - - if (!info->tty_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - retval = -ENOMEM; - goto errout; - } - - memset(info->tty_buf, 0, sizeof(struct tty_flip_buffer)); - info->tty_buf->tqueue.routine = do_ttybuf; - info->tty_buf->tqueue.data = info; - } - - info->tty_buf->count = 0; - info->tty_buf->char_buf_ptr = info->tty_buf->char_buf; - info->tty_buf->flag_buf_ptr = info->tty_buf->flag_buf; - #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d (irq %d)...", info->line, info->irq); #endif @@ -841,44 +912,45 @@ serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD2, rx_timeout); - info->stat_flags = 0; + /* clear all flags except the "never DMA" flag */ + info->stat_flags &= ESP_STAT_NEVER_DMA; + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + info->stat_flags |= ESP_STAT_USE_PIO; /* - * Allocate the IRQ if necessary + * Allocate the IRQ */ - if (!IRQ_ports[info->irq]) { - retval = request_irq(info->irq, rs_interrupt_single, - SA_INTERRUPT, "esp serial", NULL); - - if (!retval) { - int i = 1; - - while ((i < 16) && !IRQ_ports[i]) - i++; - - if (i == 16) { - dma_buffer = (char *)__get_dma_pages(GFP_KERNEL, - __get_order(DMA_BUFFER_SZ)); - if (!dma_buffer) - retval = -ENOMEM; - else - retval = request_dma(dma, "esp serial"); + retval = request_irq(info->irq, rs_interrupt_single, SA_SHIRQ, + "esp serial", info); - if (retval) - free_irq(info->irq, NULL); - } + if (retval) { + if (suser()) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; } + + restore_flags(flags); + return retval; + } - if (retval) { - if (suser()) { - if (info->tty) - set_bit(TTY_IO_ERROR, - &info->tty->flags); - retval = 0; - } - goto errout; + if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { + dma_buffer = (char *)__get_dma_pages( + GFP_KERNEL, __get_order(DMA_BUFFER_SZ)); + + /* use PIO mode if DMA buf/chan cannot be allocated */ + if (!dma_buffer) + info->stat_flags |= ESP_STAT_USE_PIO; + else if (request_dma(dma, "esp serial")) { + free_pages((unsigned int)dma_buffer, + __get_order(DMA_BUFFER_SZ)); + dma_buffer = 0; + info->stat_flags |= ESP_STAT_USE_PIO; } + } info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; @@ -899,38 +971,6 @@ clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - /* Remove port from "closed" chain */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[0] = info->next_port; - - /* - * Insert serial port into IRQ chain. - */ - next_irq = info->irq; - - do { - next_info = IRQ_ports[next_irq]; - - if (++next_irq > 15) - next_irq = 1; - } while (!next_info && (next_irq != info->irq)); - - if (!next_info) { - info->next_port = info; - info->prev_port = info; - } else { - info->next_port = next_info; - info->prev_port = next_info->prev_port; - next_info->prev_port->next_port = info; - next_info->prev_port = info; - } - - IRQ_ports[info->irq] = info; - /* * Set up the tty->alt_speed kludge */ @@ -953,10 +993,6 @@ info->flags |= ASYNC_INITIALIZED; restore_flags(flags); return 0; - -errout: - restore_flags(flags); - return retval; } /* @@ -984,67 +1020,36 @@ wake_up_interruptible(&info->delta_msr_wait); wake_up_interruptible(&info->break_wait); - /* stop a DMA transfer on the port being closed, and start the next - one */ + /* stop a DMA transfer on the port being closed */ if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { - struct esp_struct *curr = info->next_port; - disable_dma(dma); clear_dma_ff(dma); dma_bytes = 0; - - while ((curr != info) && (!dma_bytes)) { - if (curr->tty) { - if (curr->stat_flags & ESP_STAT_NEED_DMA_RX) - receive_chars_dma(curr); - if ((curr->stat_flags & ESP_STAT_NEED_DMA_TX) - && !dma_bytes) - transmit_chars_dma(curr); - } - - curr = curr->next_port; - } } /* - * First unlink the serial port from the IRQ chain... + * Free the IRQ */ - info->next_port->prev_port = info->prev_port; - info->prev_port->next_port = info->next_port; + free_irq(info->irq, info); - if (IRQ_ports[info->irq] == info) { - if ((info->next_port == info) || - (info->next_port->irq != info->irq)) - IRQ_ports[info->irq] = 0; - else - IRQ_ports[info->irq] = info->next_port; - } + if (dma_buffer) { + struct esp_struct *current_port = ports; - /* Stick it on the "closed" chain */ - info->next_port = IRQ_ports[0]; - if (info->next_port) - info->next_port->prev_port = info; - info->prev_port = 0; - IRQ_ports[0] = info; - - /* - * Free the IRQ, if necessary - */ - if (!IRQ_ports[info->irq]) { - int i = 1; + while (current_port) { + if ((current_port != info) && + (current_port->flags & ASYNC_INITIALIZED)) + break; - while ((i < 16) && !IRQ_ports[i]) - i++; + current_port = current_port->next_port; + } - if (i == 16) { + if (!current_port) { free_dma(dma); - free_pages((unsigned int)dma_buffer, - __get_order(DMA_BUFFER_SZ)); + free_pages((unsigned int)dma_buffer, + __get_order(DMA_BUFFER_SZ)); dma_buffer = 0; - } - - free_irq(info->irq, NULL); + } } if (info->xmit_buf) { @@ -1052,25 +1057,6 @@ info->xmit_buf = 0; } - if (info->tty_buf) { - /* code borrowed from tty_io.c */ - if (info->tty_buf->tqueue.sync) { - struct tq_struct *tq, *prev; - - for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { - if (tq == &info->tty_buf->tqueue) { - if (prev) - prev->next = tq->next; - else - tq_timer = tq->next; - break; - } - } - } - kfree(info->tty_buf); - info->tty_buf = 0; - } - info->IER = 0; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, 0x00); @@ -1477,9 +1463,9 @@ { struct serial_struct new_serial; struct esp_struct old_info; - unsigned int change_irq; + unsigned int change_irq; unsigned int change_flow; - int i, retval = 0; + int retval = 0; struct esp_struct *current_async; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) @@ -1522,102 +1508,97 @@ info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (new_serial.irq == 2) - new_serial.irq = 9; - - if (change_irq) { - i = 1; - - while ((i < 16) && !IRQ_ports[i]) - i++; + } else { + if (new_serial.irq == 2) + new_serial.irq = 9; - if (i < 16) { - current_async = IRQ_ports[i]; + if (change_irq) { + current_async = ports; - do { + while (current_async) { if ((current_async->line >= info->line) && (current_async->line < (info->line + 8))) { if (current_async == info) { if (current_async->count > 1) return -EBUSY; - } else + } else if (current_async->count) return -EBUSY; } current_async = current_async->next_port; - } while (current_async != IRQ_ports[i]); + } } - } - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->custom_divisor = new_serial.custom_divisor; - info->close_delay = new_serial.close_delay * HZ/100; - info->closing_wait = new_serial.closing_wait * HZ/100; - flow_off = new_serial.reserved[2]; - flow_on = new_serial.reserved[3]; - - if ((new_serial.reserved[0] != rx_trigger) || - (new_serial.reserved[1] != tx_trigger)) { - unsigned long flags; - - rx_trigger = new_serial.reserved[0]; - tx_trigger = new_serial.reserved[1]; - save_flags(flags); cli(); - serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); - serial_out(info, UART_ESI_CMD2, rx_trigger >> 8); - serial_out(info, UART_ESI_CMD2, rx_trigger); - serial_out(info, UART_ESI_CMD2, tx_trigger >> 8); - serial_out(info, UART_ESI_CMD2, tx_trigger); - restore_flags(flags); - } - if (((unsigned char)(new_serial.reserved_char[1]) != rx_timeout)) { - unsigned long flags; + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ - rx_timeout = (unsigned char)(new_serial.reserved_char[1]); - save_flags(flags); cli(); + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->custom_divisor = new_serial.custom_divisor; + info->close_delay = new_serial.close_delay * HZ/100; + info->closing_wait = new_serial.closing_wait * HZ/100; + flow_off = new_serial.reserved[2]; + flow_on = new_serial.reserved[3]; + + if ((new_serial.reserved[0] != rx_trigger) || + (new_serial.reserved[1] != tx_trigger)) { + unsigned long flags; + + rx_trigger = new_serial.reserved[0]; + tx_trigger = new_serial.reserved[1]; + save_flags(flags); cli(); + serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); + serial_out(info, UART_ESI_CMD2, rx_trigger >> 8); + serial_out(info, UART_ESI_CMD2, rx_trigger); + serial_out(info, UART_ESI_CMD2, tx_trigger >> 8); + serial_out(info, UART_ESI_CMD2, tx_trigger); + restore_flags(flags); + } + + if (((unsigned char)(new_serial.reserved_char[1]) != + rx_timeout)) { + unsigned long flags; + + rx_timeout = (unsigned char) + (new_serial.reserved_char[1]); + save_flags(flags); cli(); + + if (info->IER & UART_IER_RDI) { + serial_out(info, UART_ESI_CMD1, + ESI_SET_RX_TIMEOUT); + serial_out(info, UART_ESI_CMD2, rx_timeout); + } - if (info->IER & UART_IER_RDI) { - serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); - serial_out(info, UART_ESI_CMD2, rx_timeout); + restore_flags(flags); } - restore_flags(flags); - } + if (change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); - if (change_irq) { - /* - * We need to shutdown the serial port at the old - * port/irq combination. - */ - shutdown(info); + current_async = ports; - current_async = IRQ_ports[0]; - while (current_async != 0) { - if ((current_async->line >= info->line) && - (current_async->line < (info->line + 8))) - current_async->irq = new_serial.irq; + while (current_async) { + if ((current_async->line >= info->line) && + (current_async->line < (info->line + 8))) + current_async->irq = new_serial.irq; - current_async = current_async->next_port; - } + current_async = current_async->next_port; + } - serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); - if (info->irq == 9) - serial_out(info, UART_ESI_CMD2, 0x02); - else - serial_out(info, UART_ESI_CMD2, info->irq); + serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); + if (info->irq == 9) + serial_out(info, UART_ESI_CMD2, 0x02); + else + serial_out(info, UART_ESI_CMD2, info->irq); + } } - -check_and_exit: + if (info->flags & ASYNC_INITIALIZED) { if (((old_info.flags & ASYNC_SPD_MASK) != (info->flags & ASYNC_SPD_MASK)) || @@ -1635,6 +1616,7 @@ } } else retval = startup(info); + return retval; } @@ -2237,43 +2219,24 @@ static int esp_open(struct tty_struct *tty, struct file * filp) { struct esp_struct *info; - int i, retval, line; + int retval, line; unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; - /* check whether or not the port is on the closed chain */ + /* find the port in the chain */ - info = IRQ_ports[0]; + info = ports; while (info && (info->line != line)) info = info->next_port; - /* if the port is not on the closed chain, look for it on the */ - /* open chain */ - if (!info) { - i = 1; - - while ((i < 16) && !IRQ_ports[i]) - i++; - - if (i < 16) { - info = IRQ_ports[i]; - - do { - if (info->line == line) - break; - info = info->next_port; - } while (info != IRQ_ports[i]); - } - } - - if (!info || (info->line != line) || - serial_paranoia_check(info, tty->device, "esp_open")) + serial_paranoia_check(info, tty->device, "esp_open"); return -ENODEV; + } #ifdef SERIAL_DEBUG_OPEN printk("esp_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -2379,8 +2342,7 @@ info->irq = 4; } - if (IRQ_ports[0] && - (IRQ_ports[0]->port == (info->port - 8))) { + if (ports && (ports->port == (info->port - 8))) { release_region(*region_start, info->port - *region_start); } else @@ -2414,14 +2376,11 @@ int i, offset; int region_start; struct esp_struct * info; + struct esp_struct *last_primary = 0; int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380}; init_bh(ESP_BH, do_serial_bh); - for (i = 0; i < 16; i++) { - IRQ_ports[i] = 0; - } - for (i = 0; i < NR_PRIMARY; i++) if (irq[i] != 0) if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) || @@ -2431,7 +2390,7 @@ irq[i] = 9; if ((dma != 1) && (dma != 3)) - dma = 1; + dma = 0; if ((rx_trigger < 1) || (rx_trigger > 1023)) rx_trigger = 768; @@ -2552,21 +2511,27 @@ info->tqueue_hangup.data = info; info->callout_termios = esp_callout_driver.init_termios; info->normal_termios = esp_driver.init_termios; - - if (IRQ_ports[0]) - IRQ_ports[0]->prev_port = info; - info->next_port = IRQ_ports[0]; - info->prev_port = 0; - IRQ_ports[0] = info; + info->next_port = ports; + ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", info->line, info->port, info->irq); - if (info->line % 8) + + if (info->line % 8) { printk("secondary port\n"); - else { + /* 8 port cards can't do DMA */ + info->stat_flags |= ESP_STAT_NEVER_DMA; + + if (last_primary) + last_primary->stat_flags |= ESP_STAT_NEVER_DMA; + } else { printk("primary port\n"); + last_primary = info; irq[i] = info->irq; } + if (!dma) + info->stat_flags |= ESP_STAT_NEVER_DMA; + info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) @@ -2605,7 +2570,8 @@ unsigned long flags; int e1, e2; unsigned int region_start, region_end; - struct esp_struct *current_async, *temp_async; + struct esp_struct *temp_async; + struct esp_pio_buffer *pio_buf; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ save_flags(flags); @@ -2619,22 +2585,21 @@ e2); restore_flags(flags); - current_async = IRQ_ports[0]; - while (current_async != 0) { - if (current_async->port != 0) { - region_start = region_end = current_async->port; - temp_async = current_async; + while (ports) { + if (ports->port) { + region_start = region_end = ports->port; + temp_async = ports; - while (temp_async != 0) { + while (temp_async) { if ((region_start - temp_async->port) == 8) { region_start = temp_async->port; temp_async->port = 0; - temp_async = current_async; + temp_async = ports; } else if ((temp_async->port - region_end) == 8) { region_end = temp_async->port; temp_async->port = 0; - temp_async = current_async; + temp_async = ports; } else temp_async = temp_async->next_port; } @@ -2643,9 +2608,9 @@ region_end - region_start + 8); } - temp_async = current_async->next_port; - kfree(current_async); - current_async = temp_async; + temp_async = ports->next_port; + kfree(ports); + ports = temp_async; } if (dma_buffer) @@ -2654,5 +2619,11 @@ if (tmp_buf) free_page((unsigned long)tmp_buf); + + while (free_pio_buf) { + pio_buf = free_pio_buf->next; + kfree(free_pio_buf); + free_pio_buf = pio_buf; + } } #endif /* MODULE */ diff -u --recursive --new-file v2.1.86/linux/drivers/char/esp.h linux/drivers/char/esp.h --- v2.1.86/linux/drivers/char/esp.h Tue Dec 31 11:30:29 1996 +++ linux/drivers/char/esp.h Thu Feb 12 15:47:44 1998 @@ -46,10 +46,13 @@ #define ESI_NO_COMMAND 0xff #define ESP_STAT_RX_TIMEOUT 0x01 -#define ESP_STAT_NEED_DMA_RX 0x02 -#define ESP_STAT_NEED_DMA_TX 0x04 -#define ESP_STAT_DMA_RX 0x08 -#define ESP_STAT_DMA_TX 0x10 +#define ESP_STAT_DMA_RX 0x02 +#define ESP_STAT_DMA_TX 0x04 +#define ESP_STAT_NEVER_DMA 0x08 +#define ESP_STAT_USE_PIO 0x10 + +/* Always use PIO for this number (or less) of bytes */ +#define ESP_PIO_THRESHOLD 32 #define ESP_EVENT_WRITE_WAKEUP 0 #define ESP_MAGIC 0x53ee @@ -82,7 +85,6 @@ int xmit_head; int xmit_tail; int xmit_cnt; - struct tty_flip_buffer *tty_buf; struct tq_struct tqueue; struct tq_struct tqueue_hangup; struct termios normal_termios; @@ -93,9 +95,13 @@ struct wait_queue *break_wait; struct async_icount icount; /* kernel counters for the 4 input interrupts */ struct esp_struct *next_port; /* For the linked list */ - struct esp_struct *prev_port; }; +struct esp_pio_buffer +{ + unsigned char data[1024]; + struct esp_pio_buffer *next; +}; #endif /* ESP_H */ diff -u --recursive --new-file v2.1.86/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.1.86/linux/drivers/char/pty.c Sat Jun 28 10:31:36 1997 +++ linux/drivers/char/pty.c Thu Feb 12 16:25:04 1998 @@ -2,6 +2,9 @@ * linux/drivers/char/pty.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * Added support for a Unix98-style ptmx device. + * -- C. Scott Ananian , 14-Jan-1998 */ #include @@ -191,6 +194,45 @@ return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); } +/* + * Return the minor device number of a given pty. This lets us + * open a master pty with the multi-headed ptmx device, then + * find out which one we got after it is open, with an ioctl. + */ +static int pty_get_device_minor(struct tty_struct *tty, unsigned int *value) +{ + unsigned int result = MINOR(tty->device); + return put_user(result, value); +} +/* Set the lock flag on a pty */ +static int pty_set_lock(struct tty_struct *tty, int * arg) +{ + int val; + if (get_user(val,arg)) + return -EFAULT; + if (val) + set_bit(TTY_PTY_LOCK, &tty->flags); + else + clear_bit(TTY_PTY_LOCK, &tty->flags); + return 0; +} + +static int pty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + if (!tty) { + printk("pty_ioctl called with NULL tty!\n"); + return -EIO; + } + switch(cmd) { + case TIOCGPTN: /* Get PT Number */ + return pty_get_device_minor(tty, (unsigned int *)arg); + case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ + return pty_set_lock(tty, (int *) arg); + } + return -ENOIOCTLCMD; +} + static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; @@ -225,6 +267,8 @@ retval = -EIO; if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) goto out; + if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) + goto out; if (tty->link->count != 1) goto out; @@ -304,6 +348,12 @@ old_pty_slave_driver.minor_start = 192; old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS; old_pty_slave_driver.other = &old_pty_driver; + + /* only the master pty gets this ioctl (which is why we + * assign it here, instead of up with the rest of the + * pty_driver initialization. + */ + pty_driver.ioctl = pty_ioctl; if (tty_register_driver(&pty_driver)) panic("Couldn't register pty driver"); diff -u --recursive --new-file v2.1.86/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.86/linux/drivers/char/tty_io.c Wed Dec 31 16:40:08 1997 +++ linux/drivers/char/tty_io.c Thu Feb 12 16:25:04 1998 @@ -51,6 +51,9 @@ * * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes , June 97 + * + * Added support for a Unix98-style ptmx device. + * -- C. Scott Ananian , 14-Jan-1998 */ #include @@ -91,6 +94,7 @@ #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) #define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1) +#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2) #undef TTY_DEBUG_HANGUP @@ -1171,7 +1175,6 @@ static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; - int minor; int noctty, retval; kdev_t device; unsigned short saved_flags; @@ -1203,12 +1206,39 @@ device = c->device(c); noctty = 1; } - minor = MINOR(device); - + if (device == PTMX_DEV) { + /* find a free pty. */ + struct tty_driver *driver = tty_drivers; + int minor; + + /* find the pty driver */ + for (driver=tty_drivers; driver; driver=driver->next) + if (driver->major == PTY_MASTER_MAJOR) + break; + if (!driver) return -ENODEV; + + /* find a minor device that is not in use. */ + for (minor=driver->minor_start; + minorminor_start+driver->num; + minor++) { + device = MKDEV(driver->major, minor); + retval = init_dev(device, &tty); + if (retval==0) break; /* success! */ + } + if (minor==driver->minor_start+driver->num) /* no success */ + return -EIO; /* no free ptys */ + + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + noctty = 1; + goto init_dev_done; + } + retval = init_dev(device, &tty); if (retval) return retval; + /* N.B. this error exit may leave filp->f_flags with O_NONBLOCK set */ +init_dev_done: filp->private_data = tty; check_tty_count(tty, "tty_open"); if (tty->driver.type == TTY_DRIVER_TYPE_PTY && @@ -1932,7 +1962,7 @@ } static struct tty_driver dev_tty_driver, dev_console_driver, - dev_syscons_driver; + dev_syscons_driver, dev_ptmx_driver; /* * Ok, now we can initialize the rest of the tty devices and can count @@ -1973,6 +2003,17 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); + + dev_ptmx_driver = dev_tty_driver; + dev_ptmx_driver.driver_name = "/dev/ptmx"; + dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5; + dev_ptmx_driver.major= MAJOR(PTMX_DEV); + dev_ptmx_driver.minor_start = MINOR(PTMX_DEV); + dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM; + dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX; + + if (tty_register_driver(&dev_ptmx_driver)) + panic("Couldn't register /dev/ptmx driver\n"); #ifdef CONFIG_VT dev_console_driver = dev_tty_driver; diff -u --recursive --new-file v2.1.86/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.1.86/linux/drivers/isdn/isdn_common.c Thu Feb 12 20:56:06 1998 +++ linux/drivers/isdn/isdn_common.c Wed Feb 11 16:23:08 1998 @@ -261,10 +261,10 @@ #endif static __inline void -isdn_trash_skb(struct sk_buff *skb, int rw) +isdn_trash_skb(struct sk_buff *skb) { SET_SKB_FREE(skb); - kfree_skb(skb, rw); + kfree_skb(skb); } static void diff -u --recursive --new-file v2.1.86/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.1.86/linux/drivers/misc/parport_procfs.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/misc/parport_procfs.c Thu Feb 12 16:46:29 1998 @@ -32,7 +32,7 @@ static int irq_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { - unsigned int newirq, oldirq; + int newirq, oldirq; struct parport *pp = (struct parport *)data; if (count > 5 ) /* more than 4 digits + \n for a irq 0x?? 0?? ?? */ diff -u --recursive --new-file v2.1.86/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c --- v2.1.86/linux/drivers/pci/oldproc.c Fri Jan 30 11:28:08 1998 +++ linux/drivers/pci/oldproc.c Thu Feb 12 15:03:09 1998 @@ -70,6 +70,10 @@ DEVICE( VLSI, VLSI_82C597, "82C597-AFC2"), DEVICE( VLSI, VLSI_82C541, "82C541 Lynx"), DEVICE( VLSI, VLSI_82C543, "82C543 Lynx ISA"), + DEVICE( VLSI, VLSI_82C532, "82C532"), + DEVICE( VLSI, VLSI_82C534, "82C534"), + DEVICE( VLSI, VLSI_82C535, "82C535"), + DEVICE( VLSI, VLSI_82C147, "82C147"), DEVICE( VLSI, VLSI_VAS96011, "VAS96011 (Golden Gate II)"), DEVICE( ADL, ADL_2301, "2301"), DEVICE( NS, NS_87415, "87415"), @@ -90,6 +94,7 @@ DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"), DEVICE( DEC, DEC_21142, "DC21142"), DEVICE( DEC, DEC_21052, "DC21052"), + DEVICE( DEC, DEC_21150, "DC21150"), DEVICE( DEC, DEC_21152, "DC21152"), DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"), DEVICE( CIRRUS, CIRRUS_5430, "GD 5430"), @@ -108,10 +113,12 @@ DEVICE( IBM, IBM_FIRE_CORAL, "Fire Coral"), DEVICE( IBM, IBM_TR, "Token Ring"), DEVICE( IBM, IBM_82G2675, "82G2675"), + DEVICE( IBM, IBM_MCA, "MicroChannel"), DEVICE( IBM, IBM_82351, "82351"), DEVICE( WD, WD_7197, "WD 7197"), DEVICE( AMD, AMD_LANCE, "79C970"), DEVICE( AMD, AMD_SCSI, "53C974"), + DEVICE( TRIDENT, TRIDENT_9397, "Cyber9397"), DEVICE( TRIDENT, TRIDENT_9420, "TG 9420"), DEVICE( TRIDENT, TRIDENT_9440, "TG 9440"), DEVICE( TRIDENT, TRIDENT_9660, "TG 9660 / Cyber9385"), @@ -121,6 +128,7 @@ DEVICE( MATROX, MATROX_MIL, "Millennium"), DEVICE( MATROX, MATROX_MYS, "Mystique"), DEVICE( MATROX, MATROX_MIL_2, "Millennium II"), + DEVICE( MATROX, MATROX_MIL_2_AGP,"Millennium II AGP"), DEVICE( MATROX, MATROX_MGA_IMP, "MGA Impression"), DEVICE( CT, CT_65545, "65545"), DEVICE( CT, CT_65548, "65548"), @@ -146,6 +154,9 @@ DEVICE( HP, HP_J2585B, "J2585B (Lassen)"), DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"), DEVICE( PCTECH, PCTECH_RZ1001, "RZ1001 (buggy?)"), + DEVICE( PCTECH, PCTECH_SAMURAI_0,"Samurai 0"), + DEVICE( PCTECH, PCTECH_SAMURAI_1,"Samurai 1"), + DEVICE( PCTECH, PCTECH_SAMURAI_IDE,"Samurai IDE"), DEVICE( DPT, DPT, "SmartCache/Raid"), DEVICE( OPTI, OPTI_92C178, "92C178"), DEVICE( OPTI, OPTI_82C557, "82C557 Viper-M"), @@ -155,6 +166,7 @@ DEVICE( OPTI, OPTI_82C701, "82C701 FireStar Plus"), DEVICE( OPTI, OPTI_82C814, "82C814 Firebridge 1"), DEVICE( OPTI, OPTI_82C822, "82C822"), + DEVICE( OPTI, OPTI_82C825, "82C825 Firebridge 2"), DEVICE( SGS, SGS_2000, "STG 2000X"), DEVICE( SGS, SGS_1764, "STG 1764X"), DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"), @@ -164,6 +176,7 @@ DEVICE( TI, TI_TVP4020, "TVP4020 Permedia 2"), DEVICE( TI, TI_PCI1130, "PCI1130"), DEVICE( TI, TI_PCI1131, "PCI1131"), + DEVICE( TI, TI_PCI1250, "PCI1250"), DEVICE( OAK, OAK_OTI107, "OTI107"), DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI"), DEVICE( MOTOROLA, MOTOROLA_MPC105,"MPC105 Eagle"), @@ -216,12 +229,15 @@ DEVICE( VISION, VISION_QD8500, "QD-8500"), DEVICE( VISION, VISION_QD8580, "QD-8580"), DEVICE( BROOKTREE, BROOKTREE_848, "Bt848"), + DEVICE( BROOKTREE, BROOKTREE_849A, "Bt849"), + DEVICE( BROOKTREE, BROOKTREE_8474, "Bt8474"), DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"), DEVICE( ACC, ACC_2056, "2056"), DEVICE( WINBOND, WINBOND_83769, "W83769F"), DEVICE( WINBOND, WINBOND_82C105, "SL82C105"), DEVICE( WINBOND, WINBOND_83C553, "W83C553"), DEVICE( DATABOOK, DATABOOK_87144, "DB87144"), + DEVICE( PLX, PLX_9080, "PCI9080 I2O"), DEVICE( 3COM, 3COM_3C590, "3C590 10bT"), DEVICE( 3COM, 3COM_3C595TX, "3C595 100bTX"), DEVICE( 3COM, 3COM_3C595T4, "3C595 100bT4"), @@ -241,9 +257,11 @@ DEVICE( AL, AL_M1523, "M1523"), DEVICE( AL, AL_M1531, "M1531 Aladdin IV"), DEVICE( AL, AL_M1533, "M1533 Aladdin IV"), + DEVICE( AL, AL_M3307, "M3307 MPEG-1 decoder"), DEVICE( AL, AL_M4803, "M4803"), DEVICE( AL, AL_M5219, "M5219"), DEVICE( AL, AL_M5229, "M5229 TXpro"), + DEVICE( AL, AL_M5237, "M5237 USB"), DEVICE( SURECOM, SURECOM_NE34, "NE-34PCI LAN"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), @@ -251,6 +269,7 @@ DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( ASP, ASP_ABP940U, "ABP940U"), + DEVICE( ASP, ASP_ABP940UW, "ABP940UW"), DEVICE( CERN, CERN_SPSB_PMC, "STAR/RD24 SCI-PCI (PMC)"), DEVICE( CERN, CERN_SPSB_PCI, "STAR/RD24 SCI-PCI (PMC)"), DEVICE( IMS, IMS_8849, "8849"), @@ -265,6 +284,7 @@ DEVICE( REALTEK, REALTEK_8129, "8129"), DEVICE( TRUEVISION, TRUEVISION_T1000,"TARGA 1000"), DEVICE( INIT, INIT_320P, "320 P"), + DEVICE( INIT, INIT_360P, "360 P"), DEVICE( VIA, VIA_82C505, "VT 82C505"), DEVICE( VIA, VIA_82C561, "VT 82C561"), DEVICE( VIA, VIA_82C586_1, "VT 82C586 Apollo IDE"), @@ -272,11 +292,13 @@ DEVICE( VIA, VIA_82C585, "VT 82C585 Apollo VP1/VPX"), DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo ISA"), DEVICE( VIA, VIA_82C595, "VT 82C595 Apollo VP2"), + DEVICE( VIA, VIA_82C597_0, "VT 82C597 Apollo VP3"), DEVICE( VIA, VIA_82C926, "VT 82C926 Amazon"), DEVICE( VIA, VIA_82C416, "VT 82C416MV"), DEVICE( VIA, VIA_82C595_97, "VT 82C595 Apollo VP2/97"), DEVICE( VIA, VIA_82C586_2, "VT 82C586 Apollo USB"), DEVICE( VIA, VIA_82C586_3, "VT 82C586B Apollo ACPI"), + DEVICE( VIA, VIA_82C597_1, "VT 82C597 Apollo VP3 AGP"), DEVICE( VORTEX, VORTEX_GDT60x0, "GDT 60x0"), DEVICE( VORTEX, VORTEX_GDT6000B,"GDT 6000b"), DEVICE( VORTEX, VORTEX_GDT6x10, "GDT 6110/6510"), @@ -315,23 +337,33 @@ DEVICE( FORE, FORE_PCA200E, "PCA-200E"), DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"), DEVICE( PHILIPS, PHILIPS_SAA7146,"SAA7146"), - DEVICE( PLX, PLX_9060, "PCI9060 i960 bridge"), + DEVICE( CYCLONE, CYCLONE_SDK, "SDK"), DEVICE( ALLIANCE, ALLIANCE_PROMOTIO, "Promotion-6410"), DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), DEVICE( ALLIANCE, ALLIANCE_AT24, "AT24"), DEVICE( ALLIANCE, ALLIANCE_AT3D, "AT3D"), DEVICE( VMIC, VMIC_VME, "VMIVME-7587"), + DEVICE( DIGI, DIGI_EPC, "AccelPort EPC"), DEVICE( DIGI, DIGI_RIGHTSWITCH, "RightSwitch SE-6"), + DEVICE( DIGI, DIGI_XEM, "AccelPort Xem"), + DEVICE( DIGI, DIGI_XR, "AccelPort Xr"), + DEVICE( DIGI, DIGI_CX, "AccelPort C/X"), + DEVICE( DIGI, DIGI_XRJ, "AccelPort Xr/J"), + DEVICE( DIGI, DIGI_EPCJ, "AccelPort EPC/J"), DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), DEVICE( RENDITION, RENDITION_VERITE,"Verite 1000"), DEVICE( RENDITION, RENDITION_VERITE2100,"Verite 2100"), DEVICE( TOSHIBA, TOSHIBA_601, "Laptop"), + DEVICE( TOSHIBA, TOSHIBA_TOPIC95,"ToPIC95"), + DEVICE( TOSHIBA, TOSHIBA_TOPIC97,"ToPIC97"), DEVICE( RICOH, RICOH_RL5C466, "RL5C466"), + DEVICE( ARTOP, ARTOP_ATP850UF, "ATP850UF"), DEVICE( ZEITNET, ZEITNET_1221, "1221"), DEVICE( ZEITNET, ZEITNET_1225, "1225"), DEVICE( OMEGA, OMEGA_82C092G, "82C092G"), DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"), DEVICE( NP, NP_PCI_FDDI, "NP-PCI"), + DEVICE( ATT, ATT_L56XMF, "L56xMF"), DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"), @@ -349,11 +381,12 @@ DEVICE( CYCLADES, CYCLOM_Y_Hi, "Cyclom-Y above 1Mbyte"), DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclom-Z below 1Mbyte"), DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclom-Z above 1Mbyte"), + DEVICE( O2, O2_6832, "6832"), DEVICE( 3DFX, 3DFX_VOODOO, "Voodoo"), + DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"), DEVICE( STALLION, STALLION_ECHPCI832,"EasyConnection 8/32"), DEVICE( STALLION, STALLION_ECHPCI864,"EasyConnection 8/64"), DEVICE( STALLION, STALLION_EIOPCI,"EasyIO"), - DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"), DEVICE( OPTIBASE, OPTIBASE_FORGE, "MPEG Forge"), DEVICE( OPTIBASE, OPTIBASE_FUSION,"MPEG Fusion"), DEVICE( OPTIBASE, OPTIBASE_VPLEX, "VideoPlex"), @@ -391,6 +424,7 @@ DEVICE( S3, S3_ViRGE_MX, "ViRGE/MX"), DEVICE( S3, S3_ViRGE_MXP, "ViRGE/MX+"), DEVICE( S3, S3_ViRGE_MXPMV, "ViRGE/MX+MV"), + DEVICE( S3, S3_SONICVIBES, "SonicVibes"), DEVICE( INTEL, INTEL_82375, "82375EB"), DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"), DEVICE( INTEL, INTEL_82378, "82378IB"), @@ -615,6 +649,7 @@ case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS"; case PCI_VENDOR_ID_WINBOND: return "Winbond"; case PCI_VENDOR_ID_DATABOOK: return "Databook"; + case PCI_VENDOR_ID_PLX: return "PLX"; case PCI_VENDOR_ID_3COM: return "3Com"; case PCI_VENDOR_ID_SMC: return "SMC"; case PCI_VENDOR_ID_AL: return "Acer Labs"; @@ -638,7 +673,7 @@ case PCI_VENDOR_ID_FORE: return "Fore Systems"; case PCI_VENDOR_ID_IMAGINGTECH: return "Imaging Technology"; case PCI_VENDOR_ID_PHILIPS: return "Philips"; - case PCI_VENDOR_ID_PLX: return "PLX"; + case PCI_VENDOR_ID_CYCLONE: return "Cyclone"; case PCI_VENDOR_ID_ALLIANCE: return "Alliance"; case PCI_VENDOR_ID_VMIC: return "VMIC"; case PCI_VENDOR_ID_DIGI: return "Digi Intl."; @@ -646,10 +681,12 @@ case PCI_VENDOR_ID_RENDITION: return "Rendition"; case PCI_VENDOR_ID_TOSHIBA: return "Toshiba"; case PCI_VENDOR_ID_RICOH: return "Ricoh"; + case PCI_VENDOR_ID_ARTOP: return "Artop Electronics"; case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; case PCI_VENDOR_ID_OMEGA: return "Omega Micro"; case PCI_VENDOR_ID_LITEON: return "LiteOn"; case PCI_VENDOR_ID_NP: return "Network Peripherals"; + case PCI_VENDOR_ID_ATT: return "Lucent (ex-AT&T) Microelectronics"; case PCI_VENDOR_ID_SPECIALIX: return "Specialix"; case PCI_VENDOR_ID_AURAVISION: return "Auravision"; case PCI_VENDOR_ID_IKON: return "Ikon"; @@ -657,6 +694,7 @@ case PCI_VENDOR_ID_COMPEX: return "Compex"; case PCI_VENDOR_ID_RP: return "Comtrol"; case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; + case PCI_VENDOR_ID_O2: return "O2 Micro"; case PCI_VENDOR_ID_3DFX: return "3Dfx"; case PCI_VENDOR_ID_STALLION: return "Stallion Technologies"; case PCI_VENDOR_ID_SIGMADES: return "Sigma Designs"; @@ -868,4 +906,4 @@ return len; } -#endif +#endif /* CONFIG_PROC_FS */ diff -u --recursive --new-file v2.1.86/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.1.86/linux/drivers/sbus/char/vfc_dev.c Wed Jul 16 19:22:51 1997 +++ linux/drivers/sbus/char/vfc_dev.c Wed Feb 11 16:19:56 1998 @@ -666,9 +666,6 @@ int vfc_init(void) #endif { -#ifdef MODULE - register_symtab(0); -#endif return vfc_probe(); } diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c --- v2.1.86/linux/drivers/scsi/BusLogic.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/scsi/BusLogic.c Sat Jan 31 02:00:00 1998 @@ -6,8 +6,7 @@ This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation, provided that none of the source code or runtime - copyright notices are removed or modified. + Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY @@ -27,17 +26,17 @@ */ -#define BusLogic_DriverVersion "2.0.10" -#define BusLogic_DriverDate "11 August 1997" +#define BusLogic_DriverVersion "2.0.11" +#define BusLogic_DriverDate "31 January 1998" +#include #include #include #include #include #include #include -#include #include #include #include @@ -45,30 +44,43 @@ #include #include #include +#include #include #include "scsi.h" #include "hosts.h" #include "sd.h" #include "BusLogic.h" +#include "FlashPoint.c" /* - BusLogic_CommandLineEntryCount is a count of the number of "BusLogic=" - entries provided on the Linux Kernel Command Line. + BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver + Options specifications provided via the Linux Kernel Command Line or via + the Loadable Kernel Module Installation Facility. */ static int - BusLogic_CommandLineEntryCount = 0; + BusLogic_DriverOptionsCount = 0; /* - BusLogic_CommandLineEntries is an array of Command Line Entry structures - representing the "BusLogic=" entries provided on the Linux Kernel Command - Line. + BusLogic_DriverOptions is an array of Driver Options structures representing + BusLogic Driver Options specifications provided via the Linux Kernel Command + Line or via the Loadable Kernel Module Installation Facility. */ -static BusLogic_CommandLineEntry_T - BusLogic_CommandLineEntries[BusLogic_MaxHostAdapters]; +static BusLogic_DriverOptions_T + BusLogic_DriverOptions[BusLogic_MaxHostAdapters]; + + +/* + BusLogic_Options can be assigned a string by the Loadable Kernel Module + Installation Facility to be parsed for BusLogic Driver Options + specifications. +*/ + +static char + *BusLogic_Options = NULL; /* @@ -77,7 +89,7 @@ */ static BusLogic_ProbeOptions_T - BusLogic_ProbeOptions = { 0 }; + BusLogic_ProbeOptions = { 0 }; /* @@ -86,7 +98,17 @@ */ static BusLogic_GlobalOptions_T - BusLogic_GlobalOptions = { 0 }; + BusLogic_GlobalOptions = { 0 }; + + +/* + BusLogic_FirstRegisteredHostAdapter and BusLogic_LastRegisteredHostAdapter + are pointers to the first and last registered BusLogic Host Adapters. +*/ + +static BusLogic_HostAdapter_T + *BusLogic_FirstRegisteredHostAdapter = NULL, + *BusLogic_LastRegisteredHostAdapter = NULL; /* @@ -99,11 +121,11 @@ /* - BusLogic_ProbeInfoCount is the numbers of entries in BusLogic_ProbeInfoList. + BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList. */ static int - BusLogic_ProbeInfoCount = 0; + BusLogic_ProbeInfoCount = 0; /* @@ -114,7 +136,7 @@ */ static BusLogic_ProbeInfo_T - BusLogic_ProbeInfoList[BusLogic_MaxHostAdapters] = { { 0 } }; + *BusLogic_ProbeInfoList = NULL; /* @@ -133,8 +155,8 @@ */ static BusLogic_CCB_T - *BusLogic_FirstCompletedCCB = NULL, - *BusLogic_LastCompletedCCB = NULL; + *BusLogic_FirstCompletedCCB = NULL, + *BusLogic_LastCompletedCCB = NULL; /* @@ -181,6 +203,17 @@ static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter) { + HostAdapter->NextAll = NULL; + if (BusLogic_FirstRegisteredHostAdapter == NULL) + { + BusLogic_FirstRegisteredHostAdapter = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } + else + { + BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } HostAdapter->Next = NULL; if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL) { @@ -202,14 +235,33 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter) { + if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) + { + BusLogic_FirstRegisteredHostAdapter = + BusLogic_FirstRegisteredHostAdapter->NextAll; + if (HostAdapter == BusLogic_LastRegisteredHostAdapter) + BusLogic_LastRegisteredHostAdapter = NULL; + } + else + { + BusLogic_HostAdapter_T *PreviousHostAdapter = + BusLogic_FirstRegisteredHostAdapter; + while (PreviousHostAdapter != NULL && + PreviousHostAdapter->NextAll != HostAdapter) + PreviousHostAdapter = PreviousHostAdapter->NextAll; + if (PreviousHostAdapter != NULL) + PreviousHostAdapter->NextAll = HostAdapter->NextAll; + } + HostAdapter->NextAll = NULL; if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter) { - BusLogic_HostAdapter_T *LastHostAdapter = + BusLogic_HostAdapter_T *PreviousHostAdapter = BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel]; - while (LastHostAdapter != NULL && LastHostAdapter->Next != HostAdapter) - LastHostAdapter = LastHostAdapter->Next; - if (LastHostAdapter != NULL) - LastHostAdapter->Next = HostAdapter->Next; + while (PreviousHostAdapter != NULL && + PreviousHostAdapter->Next != HostAdapter) + PreviousHostAdapter = PreviousHostAdapter->Next; + if (PreviousHostAdapter != NULL) + PreviousHostAdapter->Next = HostAdapter->Next; } else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] = HostAdapter->Next; @@ -218,85 +270,33 @@ /* - BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for - Host Adapter. -*/ - -static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter) -{ - /* - FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Allocate space for the Outgoing and Incoming Mailboxes. - */ - HostAdapter->FirstOutgoingMailbox = - (BusLogic_OutgoingMailbox_T *) - scsi_init_malloc(HostAdapter->MailboxCount - * (sizeof(BusLogic_OutgoingMailbox_T) - + sizeof(BusLogic_IncomingMailbox_T)), - (HostAdapter->BounceBuffersRequired - ? GFP_ATOMIC | GFP_DMA - : GFP_ATOMIC)); - if (HostAdapter->FirstOutgoingMailbox == NULL) - { - BusLogic_Error("UNABLE TO ALLOCATE MAILBOXES - DETACHING\n", - HostAdapter, HostAdapter->HostNumber); - return false; - } - HostAdapter->LastOutgoingMailbox = - HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->FirstIncomingMailbox = - (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1); - HostAdapter->LastIncomingMailbox = - HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; - return true; -} - - -/* - BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes - for Host Adapter. -*/ - -static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter) -{ - if (HostAdapter->FirstOutgoingMailbox == NULL) return; - scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox, - HostAdapter->MailboxCount - * (sizeof(BusLogic_OutgoingMailbox_T) - + sizeof(BusLogic_IncomingMailbox_T))); -} - - -/* - BusLogic_CreateCCB allocates and initializes a single Command Control - Block (CCB) for Host Adapter, and adds it to Host Adapter's free list. -*/ - -static boolean BusLogic_CreateCCB(BusLogic_HostAdapter_T *HostAdapter) -{ - BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) - scsi_init_malloc(sizeof(BusLogic_CCB_T), - (HostAdapter->BounceBuffersRequired - ? GFP_ATOMIC | GFP_DMA - : GFP_ATOMIC)); - if (CCB == NULL) return false; - memset(CCB, 0, sizeof(BusLogic_CCB_T)); - CCB->HostAdapter = HostAdapter; - CCB->Status = BusLogic_CCB_Free; - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - CCB->CallbackFunction = BusLogic_QueueCompletedCCB; - CCB->BaseAddress = HostAdapter->IO_Address; + BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs) + for Host Adapter from the BlockSize bytes located at BlockPointer. The newly + created CCBs are added to Host Adapter's free list. +*/ + +static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter, + void *BlockPointer, int BlockSize) +{ + BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer; + memset(BlockPointer, 0, BlockSize); + CCB->AllocationGroupHead = true; + while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0) + { + CCB->Status = BusLogic_CCB_Free; + CCB->HostAdapter = HostAdapter; + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + { + CCB->CallbackFunction = BusLogic_QueueCompletedCCB; + CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; + } + CCB->Next = HostAdapter->Free_CCBs; + CCB->NextAll = HostAdapter->All_CCBs; + HostAdapter->Free_CCBs = CCB; + HostAdapter->All_CCBs = CCB; + HostAdapter->AllocatedCCBs++; + CCB++; } - CCB->Next = HostAdapter->Free_CCBs; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->Free_CCBs = CCB; - HostAdapter->All_CCBs = CCB; - HostAdapter->AllocatedCCBs++; - return true; } @@ -306,14 +306,21 @@ static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter) { - int Allocated; - for (Allocated = 0; Allocated < HostAdapter->InitialCCBs; Allocated++) - if (!BusLogic_CreateCCB(HostAdapter)) - { - BusLogic_Error("UNABLE TO ALLOCATE CCB %d - DETACHING\n", - HostAdapter, Allocated); - return false; - } + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); + while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) + { + void *BlockPointer = kmalloc(BlockSize, + (HostAdapter->BounceBuffersRequired + ? GFP_ATOMIC | GFP_DMA + : GFP_ATOMIC)); + if (BlockPointer == NULL) + { + BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", + HostAdapter); + return false; + } + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); + } return true; } @@ -330,7 +337,8 @@ while ((CCB = NextCCB) != NULL) { NextCCB = CCB->NextAll; - scsi_init_free((char *) CCB, sizeof(BusLogic_CCB_T)); + if (CCB->AllocationGroupHead) + kfree(CCB); } } @@ -346,18 +354,35 @@ int AdditionalCCBs, boolean SuccessMessageP) { - int Allocated; + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); + int PreviouslyAllocated = HostAdapter->AllocatedCCBs; if (AdditionalCCBs <= 0) return; - for (Allocated = 0; Allocated < AdditionalCCBs; Allocated++) - if (!BusLogic_CreateCCB(HostAdapter)) break; - if (Allocated > 0 && SuccessMessageP) - BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", - HostAdapter, Allocated, HostAdapter->AllocatedCCBs); - if (Allocated > 0) return; + while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) + { + void *BlockPointer = kmalloc(BlockSize, + (HostAdapter->BounceBuffersRequired + ? GFP_ATOMIC | GFP_DMA + : GFP_ATOMIC)); + if (BlockPointer == NULL) break; + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); + } + if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) + { + if (SuccessMessageP) + BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", + HostAdapter, + HostAdapter->AllocatedCCBs - PreviouslyAllocated, + HostAdapter->AllocatedCCBs); + return; + } BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); - HostAdapter->DriverQueueDepth = - HostAdapter->AllocatedCCBs - (HostAdapter->MaxTargetDevices - 1); - HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; + if (HostAdapter->DriverQueueDepth > + HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) + { + HostAdapter->DriverQueueDepth = + HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; + HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; + } } @@ -413,47 +438,6 @@ /* - BusLogic_CreateTargetDeviceStatistics creates the Target Device Statistics - structure for Host Adapter. -*/ - -static boolean BusLogic_CreateTargetDeviceStatistics(BusLogic_HostAdapter_T - *HostAdapter) -{ - HostAdapter->TargetDeviceStatistics = - (BusLogic_TargetDeviceStatistics_T *) - scsi_init_malloc(HostAdapter->MaxTargetDevices - * sizeof(BusLogic_TargetDeviceStatistics_T), - GFP_ATOMIC); - if (HostAdapter->TargetDeviceStatistics == NULL) - { - BusLogic_Error("UNABLE TO ALLOCATE TARGET DEVICE STATISTICS - " - "DETACHING\n", HostAdapter, HostAdapter->HostNumber); - return false; - } - memset(HostAdapter->TargetDeviceStatistics, 0, - HostAdapter->MaxTargetDevices - * sizeof(BusLogic_TargetDeviceStatistics_T)); - return true; -} - - -/* - BusLogic_DestroyTargetDeviceStatistics destroys the Target Device Statistics - structure for Host Adapter. -*/ - -static void BusLogic_DestroyTargetDeviceStatistics(BusLogic_HostAdapter_T - *HostAdapter) -{ - if (HostAdapter->TargetDeviceStatistics == NULL) return; - scsi_init_free((char *) HostAdapter->TargetDeviceStatistics, - HostAdapter->MaxTargetDevices - * sizeof(BusLogic_TargetDeviceStatistics_T)); -} - - -/* BusLogic_Command sends the command OperationCode to HostAdapter, optionally providing ParameterLength bytes of ParameterData and receiving at most ReplyLength bytes of ReplyData; any excess reply data is received but @@ -494,7 +478,7 @@ If the IRQ Channel has not yet been acquired, then interrupts must be disabled while issuing host adapter commands since a Command Complete interrupt could occur if the IRQ Channel was previously enabled by another - BusLogic Host Adapter or other driver sharing the same IRQ Channel. + BusLogic Host Adapter or another driver sharing the same IRQ Channel. */ if (!HostAdapter->IRQ_ChannelAcquired) { @@ -572,7 +556,7 @@ Result = -1; goto Done; } - if (BusLogic_GlobalOptions.Bits.TraceConfiguration) + if (BusLogic_GlobalOptions.TraceConfiguration) BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All); @@ -607,9 +591,11 @@ if (InterruptRegister.Bits.CommandComplete) break; if (HostAdapter->HostAdapterCommandCompleted) break; if (StatusRegister.Bits.DataInRegisterReady) - if (++ReplyBytes <= ReplyLength) - *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); - else BusLogic_ReadDataInRegister(HostAdapter); + { + if (++ReplyBytes <= ReplyLength) + *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); + else BusLogic_ReadDataInRegister(HostAdapter); + } if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.Bits.HostAdapterReady) break; udelay(100); @@ -621,34 +607,24 @@ goto Done; } /* - If testing Command Complete Interrupts, wait a short while in case the - loop immediately above terminated due to the Command Complete bit being - set in the Interrupt Register, but the interrupt hasn't actually been - processed yet. Otherwise, acknowledging the interrupt here could prevent - the interrupt test from succeeding. - */ - if (OperationCode == BusLogic_TestCommandCompleteInterrupt) - udelay(10000); - /* Clear any pending Command Complete Interrupt. */ BusLogic_InterruptReset(HostAdapter); /* Provide tracing information if requested. */ - if (BusLogic_GlobalOptions.Bits.TraceConfiguration) - if (OperationCode != BusLogic_TestCommandCompleteInterrupt) - { - int i; - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", - HostAdapter, OperationCode, - StatusRegister.All, ReplyLength, ReplyBytes); - if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; - for (i = 0; i < ReplyLength; i++) - BusLogic_Notice(" %02X", HostAdapter, - ((unsigned char *) ReplyData)[i]); - BusLogic_Notice("\n", HostAdapter); - } + if (BusLogic_GlobalOptions.TraceConfiguration) + { + int i; + BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", + HostAdapter, OperationCode, + StatusRegister.All, ReplyLength, ReplyBytes); + if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; + for (i = 0; i < ReplyLength; i++) + BusLogic_Notice(" %02X", HostAdapter, + ((unsigned char *) ReplyData)[i]); + BusLogic_Notice("\n", HostAdapter); + } /* Process Command Invalid conditions. */ @@ -705,38 +681,63 @@ /* + BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list + of I/O Address and Bus Probe Information to be checked for potential BusLogic + Host Adapters. +*/ + +static void BusLogic_AppendProbeAddressISA(BusLogic_IO_Address_T IO_Address) +{ + BusLogic_ProbeInfo_T *ProbeInfo; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return; + ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_MultiMaster; + ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + ProbeInfo->IO_Address = IO_Address; +} + + +/* BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters only from the list of standard BusLogic MultiMaster ISA I/O Addresses. */ -static void BusLogic_InitializeProbeInfoListISA(void) +static void BusLogic_InitializeProbeInfoListISA(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { - int StandardAddressIndex; - /* - If BusLogic_Setup has provided an I/O Address probe list, do not override - the Kernel Command Line specifications. - */ - if (BusLogic_ProbeInfoCount > 0) return; /* - If a Kernel Command Line specification has requested that ISA Bus Probes + If BusLogic Driver Options specifications requested that ISA Bus Probes be inhibited, do not proceed further. */ - if (BusLogic_ProbeOptions.Bits.NoProbeISA) return; + if (BusLogic_ProbeOptions.NoProbeISA) return; /* Append the list of standard BusLogic MultiMaster ISA I/O Addresses. */ - StandardAddressIndex = 0; - while (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters && - StandardAddressIndex < BusLogic_ISA_StandardAddressesCount) - { - BusLogic_ProbeInfo_T *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = - BusLogic_ISA_StandardAddresses[StandardAddressIndex++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe330 + : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x330); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe334 + : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x334); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe230 + : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x230); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe234 + : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x234); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe130 + : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x130); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe134 + : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x134); } @@ -783,25 +784,26 @@ I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found. */ -static int BusLogic_InitializeMultiMasterProbeInfo(void) +static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { - boolean StandardAddressSeen[BusLogic_ISA_StandardAddressesCount]; BusLogic_ProbeInfo_T *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; boolean ForceBusDeviceScanningOrder = false; boolean ForceBusDeviceScanningOrderChecked = false; - unsigned char Bus, DeviceFunction, IRQ_Channel; + boolean StandardAddressSeen[6]; + unsigned char Bus, DeviceFunction; unsigned int BaseAddress0, BaseAddress1; + unsigned char IRQ_Channel; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; unsigned short Index = 0; - int StandardAddressIndex, i; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) - return 0; + int i; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0; BusLogic_ProbeInfoCount++; - for (i = 0; i < BusLogic_ISA_StandardAddressesCount; i++) + for (i = 0; i < 6; i++) StandardAddressSeen[i] = false; /* Iterate over the MultiMaster PCI Host Adapters. For each enumerated host @@ -826,8 +828,7 @@ pcibios_read_config_byte(Bus, DeviceFunction, PCI_INTERRUPT_LINE, &IRQ_Channel) == 0) { - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; + BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation; BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; unsigned char Device = DeviceFunction >> 3; @@ -859,7 +860,7 @@ NULL, Bus, Device, IO_Address); continue; } - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) { BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL); @@ -871,7 +872,7 @@ Issue the Inquire PCI Host Adapter Information command to determine the ISA Compatible I/O Port. If the ISA Compatible I/O Port is known and enabled, note that the particular Standard ISA I/O - Address need not be probed. + Address should not be probed. */ HostAdapter->IO_Address = IO_Address; if (BusLogic_Command(HostAdapter, @@ -880,8 +881,7 @@ sizeof(PCIHostAdapterInformation)) == sizeof(PCIHostAdapterInformation)) { - if (PCIHostAdapterInformation.ISACompatibleIOPort < - BusLogic_ISA_StandardAddressesCount) + if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) StandardAddressSeen[PCIHostAdapterInformation .ISACompatibleIOPort] = true; } @@ -933,10 +933,10 @@ */ if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) { - PrimaryProbeInfo->IO_Address = IO_Address; - PrimaryProbeInfo->PCI_Address = PCI_Address; PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + PrimaryProbeInfo->IO_Address = IO_Address; + PrimaryProbeInfo->PCI_Address = PCI_Address; PrimaryProbeInfo->Bus = Bus; PrimaryProbeInfo->Device = Device; PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; @@ -946,10 +946,10 @@ { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->HostAdapterType = BusLogic_MultiMaster; ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; @@ -978,31 +978,48 @@ then the Primary I/O Address must be probed explicitly before any PCI host adapters are probed. */ - if (PrimaryProbeInfo->IO_Address == 0 && - !BusLogic_ProbeOptions.Bits.NoProbeISA) - { - PrimaryProbeInfo->IO_Address = BusLogic_ISA_StandardAddresses[0]; - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } + if (!BusLogic_ProbeOptions.NoProbeISA) + if (PrimaryProbeInfo->IO_Address == 0 && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe330 + : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) + { + PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; + PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + PrimaryProbeInfo->IO_Address = 0x330; + } /* Append the list of standard BusLogic MultiMaster ISA I/O Addresses, omitting the Primary I/O Address which has already been handled. */ - if (!BusLogic_ProbeOptions.Bits.NoProbeISA) - for (StandardAddressIndex = 1; - StandardAddressIndex < BusLogic_ISA_StandardAddressesCount; - StandardAddressIndex++) - if (!StandardAddressSeen[StandardAddressIndex] && - BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) - { - BusLogic_ProbeInfo_T *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = - BusLogic_ISA_StandardAddresses[StandardAddressIndex]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } + if (!BusLogic_ProbeOptions.NoProbeISA) + { + if (!StandardAddressSeen[1] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe334 + : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x334); + if (!StandardAddressSeen[2] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe230 + : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x230); + if (!StandardAddressSeen[3] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe234 + : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x234); + if (!StandardAddressSeen[4] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe130 + : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x130); + if (!StandardAddressSeen[5] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe134 + : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x134); + } return PCIMultiMasterCount; } @@ -1014,11 +1031,13 @@ number of FlashPoint Host Adapters found. */ -static int BusLogic_InitializeFlashPointProbeInfo(void) +static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; - unsigned char Bus, DeviceFunction, IRQ_Channel; + unsigned char Bus, DeviceFunction; unsigned int BaseAddress0, BaseAddress1; + unsigned char IRQ_Channel; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; unsigned short Index = 0; @@ -1065,7 +1084,7 @@ NULL, Bus, Device, IO_Address); continue; } - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) { BusLogic_Notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL); @@ -1077,10 +1096,10 @@ { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->HostAdapterType = BusLogic_FlashPoint; ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; @@ -1116,44 +1135,41 @@ FlashPoint and PCI MultiMaster Host Adapters are present, this driver will probe for FlashPoint Host Adapters first unless the BIOS primary disk is controlled by the first PCI MultiMaster Host Adapter, in which case - MultiMaster Host Adapters will be probed first. The Kernel Command Line - options "MultiMasterFirst" and "FlashPointFirst" can be used to force a - particular probe order. + MultiMaster Host Adapters will be probed first. The BusLogic Driver Options + specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force + a particular probe order. */ -static void BusLogic_InitializeProbeInfoList(void) +static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { /* - If BusLogic_Setup has provided an I/O Address probe list, do not override - the Kernel Command Line specifications. - */ - if (BusLogic_ProbeInfoCount > 0) return; - /* If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint Host Adapters; otherwise, default to the standard ISA MultiMaster probe. */ - if (!BusLogic_ProbeOptions.Bits.NoProbePCI && pcibios_present()) + if (!BusLogic_ProbeOptions.NoProbePCI && pcibios_present()) { - if (BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst) + if (BusLogic_ProbeOptions.MultiMasterFirst) { - BusLogic_InitializeMultiMasterProbeInfo(); - BusLogic_InitializeFlashPointProbeInfo(); + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); } - else if (BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst) + else if (BusLogic_ProbeOptions.FlashPointFirst) { - BusLogic_InitializeFlashPointProbeInfo(); - BusLogic_InitializeMultiMasterProbeInfo(); + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); } else { - int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo(); - int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo(); + int FlashPointCount = + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + int PCIMultiMasterCount = + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); if (FlashPointCount > 0 && PCIMultiMasterCount > 0) { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[FlashPointCount]; - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; + BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; BusLogic_FetchHostAdapterLocalRAMRequest_T FetchHostAdapterLocalRAMRequest; BusLogic_BIOSDriveMapByte_T Drive0MapByte; @@ -1195,7 +1211,7 @@ } } } - else BusLogic_InitializeProbeInfoListISA(); + else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); } @@ -1240,20 +1256,14 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - FlashPoint_Info_T *FlashPointInfo = (FlashPoint_Info_T *) - scsi_init_malloc(sizeof(FlashPoint_Info_T), GFP_ATOMIC); - int Retries = 10; - if (FlashPointInfo == NULL) - return BusLogic_Failure(HostAdapter, "ALLOCATING FLASHPOINT INFO"); - FlashPointInfo->BaseAddress = HostAdapter->IO_Address; + FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->BaseAddress = + (BusLogic_Base_Address_T) HostAdapter->IO_Address; FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; FlashPointInfo->Present = false; - while (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && - FlashPointInfo->Present) && - --Retries >= 0) ; - if (!FlashPointInfo->Present) + if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && + FlashPointInfo->Present)) { - scsi_init_free((char *) FlashPointInfo, sizeof(FlashPoint_Info_T)); BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device); @@ -1264,8 +1274,7 @@ HostAdapter); return false; } - HostAdapter->FlashPointInfo = FlashPointInfo; - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", HostAdapter, HostAdapter->IO_Address); /* @@ -1283,7 +1292,7 @@ StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All, @@ -1318,12 +1327,16 @@ /* - BusLogic_HardResetHostAdapter issues a Hard Reset to the Host Adapter, - and waits for Host Adapter Diagnostics to complete. + BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter + and waits for Host Adapter Diagnostics to complete. If HardReset is true, a + Hard Reset is performed which also initiates a SCSI Bus Reset. Otherwise, a + Soft Reset is performed which only resets the Host Adapter without forcing a + SCSI Bus Reset. */ -static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T - *HostAdapter) +static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T + *HostAdapter, + boolean HardReset) { BusLogic_StatusRegister_T StatusRegister; int TimeoutCounter; @@ -1332,9 +1345,11 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - HostAdapter->FlashPointInfo->ReportDataUnderrun = true; + FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->HostSoftReset = !HardReset; + FlashPointInfo->ReportDataUnderrun = true; HostAdapter->CardHandle = - FlashPoint_HardResetHostAdapter(HostAdapter->FlashPointInfo); + FlashPoint_HardwareResetHostAdapter(FlashPointInfo); if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false; /* Indicate the Host Adapter Hard Reset completed successfully. @@ -1342,10 +1357,12 @@ return true; } /* - Issue a Hard Reset Command to the Host Adapter. The Host Adapter should - respond by setting Diagnostic Active in the Status Register. + Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host + Adapter should respond by setting Diagnostic Active in the Status Register. */ - BusLogic_HardReset(HostAdapter); + if (HardReset) + BusLogic_HardReset(HostAdapter); + else BusLogic_SoftReset(HostAdapter); /* Wait until Diagnostic Active is set in the Status Register. */ @@ -1356,8 +1373,8 @@ if (StatusRegister.Bits.DiagnosticActive) break; udelay(100); } - if (BusLogic_GlobalOptions.Bits.TraceHardReset) - BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Active, " + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); if (TimeoutCounter < 0) return false; @@ -1377,8 +1394,8 @@ if (!StatusRegister.Bits.DiagnosticActive) break; udelay(100); } - if (BusLogic_GlobalOptions.Bits.TraceHardReset) - BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Completed, " + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); if (TimeoutCounter < 0) return false; @@ -1396,8 +1413,8 @@ break; udelay(100); } - if (BusLogic_GlobalOptions.Bits.TraceHardReset) - BusLogic_Notice("BusLogic_HardReset(0x%X): Host Adapter Ready, " + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); if (TimeoutCounter < 0) return false; @@ -1447,25 +1464,27 @@ Issue the Inquire Configuration command if the IRQ Channel is unknown. */ if (HostAdapter->IRQ_Channel == 0) - if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, - NULL, 0, &Configuration, sizeof(Configuration)) - == sizeof(Configuration)) - { - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - else Result = false; - } - else Result = false; + { + if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, + NULL, 0, &Configuration, sizeof(Configuration)) + == sizeof(Configuration)) + { + if (Configuration.IRQ_Channel9) + HostAdapter->IRQ_Channel = 9; + else if (Configuration.IRQ_Channel10) + HostAdapter->IRQ_Channel = 10; + else if (Configuration.IRQ_Channel11) + HostAdapter->IRQ_Channel = 11; + else if (Configuration.IRQ_Channel12) + HostAdapter->IRQ_Channel = 12; + else if (Configuration.IRQ_Channel14) + HostAdapter->IRQ_Channel = 14; + else if (Configuration.IRQ_Channel15) + HostAdapter->IRQ_Channel = 15; + else Result = false; + } + else Result = false; + } /* Issue the Inquire Extended Setup Information command. Only genuine BusLogic Host Adapters and true clones support this command. Adaptec 1542C @@ -1484,7 +1503,7 @@ /* Provide tracing information if requested and return. */ - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); return Result; @@ -1512,7 +1531,7 @@ BusLogic_GeometryRegister_T GeometryRegister; BusLogic_RequestedReplyLength_T RequestedReplyLength; unsigned char *TargetPointer, Character; - int i; + int TargetID, i; /* Configuration Information for FlashPoint Host Adapters is provided in the FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. @@ -1521,7 +1540,7 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - FlashPoint_Info_T *FlashPointInfo = HostAdapter->FlashPointInfo; + FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo; TargetPointer = HostAdapter->ModelName; *TargetPointer++ = 'B'; *TargetPointer++ = 'T'; @@ -1550,8 +1569,8 @@ HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); HostAdapter->MaxLogicalUnits = 32; - HostAdapter->InitialCCBs = 64; - HostAdapter->IncrementalCCBs = 16; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; HostAdapter->DriverQueueDepth = 255; HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; @@ -1698,12 +1717,14 @@ HostAdapter->HostAdapterBusType = BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; + { + if (Configuration.DMA_Channel5) + HostAdapter->DMA_Channel = 5; + else if (Configuration.DMA_Channel6) + HostAdapter->DMA_Channel = 6; + else if (Configuration.DMA_Channel7) + HostAdapter->DMA_Channel = 7; + } /* Determine whether Extended Translation is enabled and save it in the Host Adapter structure. @@ -1837,7 +1858,7 @@ HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); /* - Select appropriate values for the Driver Queue Depth, Mailbox Count, + Select appropriate values for the Mailbox Count, Driver Queue Depth, Initial CCBs, and Incremental CCBs variables based on whether or not Strict Round Robin Mode is supported. If Strict Round Robin Mode is supported, then there is no performance degradation in using the maximum possible @@ -1868,18 +1889,16 @@ if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) { HostAdapter->StrictRoundRobinModeSupport = true; - HostAdapter->MailboxCount = 255; - HostAdapter->InitialCCBs = 64; - HostAdapter->IncrementalCCBs = 16; + HostAdapter->MailboxCount = BusLogic_MaxMailboxes; } else { HostAdapter->StrictRoundRobinModeSupport = false; HostAdapter->MailboxCount = 32; - HostAdapter->InitialCCBs = 32; - HostAdapter->IncrementalCCBs = 8; } HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; /* Tagged Queuing support is available and operates properly on all "W" series MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with @@ -1931,57 +1950,32 @@ */ Common: /* - Initialize the Host Adapter Name and Interrupt Label fields from the - Model Name. + Initialize the Host Adapter Full Model Name and Interrupt Label fields + from the Model Name. */ strcpy(HostAdapter->FullModelName, "BusLogic "); strcat(HostAdapter->FullModelName, HostAdapter->ModelName); strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName); /* Select an appropriate value for the Tagged Queue Depth either from a - Command Line Entry, or based on whether this Host Adapter requires that ISA - Bounce Buffers be used. The Tagged Queue Depth is left at 0 for automatic - determination in BusLogic_SelectQueueDepths. Initialize the Untagged Queue - Depth. Tagged Queuing is disabled by default when the Tagged Queue Depth - is 1 since queuing multiple commands is not possible. - */ - if (HostAdapter->CommandLineEntry != NULL && - HostAdapter->CommandLineEntry->TaggedQueueDepth > 0) - HostAdapter->TaggedQueueDepth = - HostAdapter->CommandLineEntry->TaggedQueueDepth; - else if (HostAdapter->BounceBuffersRequired) - HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthBounceBuffers; - else HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthAutomatic; - HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; - if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth && - HostAdapter->TaggedQueueDepth > 0) - HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth; - if (HostAdapter->TaggedQueueDepth == 1) - HostAdapter->TaggedQueuingPermitted = 0; - /* - Select an appropriate value for Bus Settle Time either from a Command - Line Entry, or from BusLogic_DefaultBusSettleTime. - */ - if (HostAdapter->CommandLineEntry != NULL && - HostAdapter->CommandLineEntry->BusSettleTime > 0) - HostAdapter->BusSettleTime = HostAdapter->CommandLineEntry->BusSettleTime; - else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; - /* - Select an appropriate value for Local Options from a Command Line Entry. - */ - if (HostAdapter->CommandLineEntry != NULL) - HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions; - /* - Select appropriate values for the Error Recovery Strategy array either from - a Command Line Entry, or using BusLogic_ErrorRecovery_Default. - */ - if (HostAdapter->CommandLineEntry != NULL) - memcpy(HostAdapter->ErrorRecoveryStrategy, - HostAdapter->CommandLineEntry->ErrorRecoveryStrategy, - sizeof(HostAdapter->ErrorRecoveryStrategy)); - else memset(HostAdapter->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_Default, - sizeof(HostAdapter->ErrorRecoveryStrategy)); + BusLogic Driver Options specification, or based on whether this Host + Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth + is left at 0 for automatic determination in BusLogic_SelectQueueDepths. + Initialize the Untagged Queue Depth. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + { + unsigned char QueueDepth = 0; + if (HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) + QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; + else if (HostAdapter->BounceBuffersRequired) + QueueDepth = BusLogic_TaggedQueueDepthBB; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + } + if (HostAdapter->BounceBuffersRequired) + HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; + else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; /* Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. Therefore, mask the Tagged Queuing Permitted Default bits with the @@ -1989,15 +1983,34 @@ */ HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; /* - Combine the default Tagged Queuing Permitted bits with any Command - Line Entry Tagged Queuing specification. + Combine the default Tagged Queuing Permitted bits with any BusLogic Driver + Options Tagged Queuing specification. */ - if (HostAdapter->CommandLineEntry != NULL) + if (HostAdapter->DriverOptions != NULL) HostAdapter->TaggedQueuingPermitted = - (HostAdapter->CommandLineEntry->TaggedQueuingPermitted & - HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask) | + (HostAdapter->DriverOptions->TaggedQueuingPermitted & + HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | (HostAdapter->TaggedQueuingPermitted & - ~HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask); + ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); + /* + Select appropriate values for the Error Recovery Strategy array + either from a BusLogic Driver Options specification, or using + BusLogic_ErrorRecovery_Default. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + if (HostAdapter->DriverOptions != NULL) + HostAdapter->ErrorRecoveryStrategy[TargetID] = + HostAdapter->DriverOptions->ErrorRecoveryStrategy[TargetID]; + else HostAdapter->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + /* + Select an appropriate value for Bus Settle Time either from a BusLogic + Driver Options specification, or from BusLogic_DefaultBusSettleTime. + */ + if (HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->BusSettleTime > 0) + HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; + else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; /* Indicate reading the Host Adapter Configuration completed successfully. */ @@ -2017,7 +2030,8 @@ unsigned short SynchronousPermitted, FastPermitted; unsigned short UltraPermitted, WidePermitted; unsigned short DisconnectPermitted, TaggedQueuingPermitted; - boolean CommonSynchronousNegotiation, CommonErrorRecovery; + boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; + boolean CommonErrorRecovery; char SynchronousString[BusLogic_MaxTargetDevices+1]; char WideString[BusLogic_MaxTargetDevices+1]; char DisconnectString[BusLogic_MaxTargetDevices+1]; @@ -2083,22 +2097,26 @@ CommonSynchronousNegotiation = true; } else if (SynchronousPermitted == AllTargetsMask) - if (FastPermitted == 0) - { - SynchronousMessage = "Slow"; - CommonSynchronousNegotiation = true; - } - else if (FastPermitted == AllTargetsMask) - if (UltraPermitted == 0) + { + if (FastPermitted == 0) { - SynchronousMessage = "Fast"; + SynchronousMessage = "Slow"; CommonSynchronousNegotiation = true; } - else if (UltraPermitted == AllTargetsMask) + else if (FastPermitted == AllTargetsMask) { - SynchronousMessage = "Ultra"; - CommonSynchronousNegotiation = true; + if (UltraPermitted == 0) + { + SynchronousMessage = "Fast"; + CommonSynchronousNegotiation = true; + } + else if (UltraPermitted == AllTargetsMask) + { + SynchronousMessage = "Ultra"; + CommonSynchronousNegotiation = true; + } } + } if (!CommonSynchronousNegotiation) { for (TargetID = 0; @@ -2175,9 +2193,20 @@ HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->DriverScatterGatherLimit); BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); - if (HostAdapter->TaggedQueueDepth > 0) - BusLogic_Info("%d", HostAdapter, HostAdapter->TaggedQueueDepth); - else BusLogic_Info("Automatic", HostAdapter); + CommonTaggedQueueDepth = true; + for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) + { + CommonTaggedQueueDepth = false; + break; + } + if (CommonTaggedQueueDepth) + { + if (HostAdapter->QueueDepth[0] > 0) + BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); + else BusLogic_Info("Automatic", HostAdapter); + } + else BusLogic_Info("Individual", HostAdapter); BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, HostAdapter->UntaggedQueueDepth); CommonErrorRecovery = true; @@ -2314,51 +2343,6 @@ /* - BusLogic_TestInterrupts tests for proper functioning of the Host Adapter - Interrupt Register and that interrupts generated by the Host Adapter are - getting through to the Interrupt Handler. A large proportion of initial - problems with installing PCI Host Adapters are due to configuration problems - where either the Host Adapter or Motherboard is configured incorrectly, and - interrupts do not get through as a result. -*/ - -static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter) -{ - unsigned int InitialInterruptCount, FinalInterruptCount; - int TestCount = 5, i; - /* - FlashPoint Host Adapters do not provide for an interrupt test. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Inhibit the Interrupt Test if requested. - */ - if (HostAdapter->LocalOptions.Bits.InhibitInterruptTest) return true; - /* - Issue the Test Command Complete Interrupt commands. - */ - - InitialInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel); - for (i = 0; i < TestCount; i++) - BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt, - NULL, 0, NULL, 0); - FinalInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel); - /* - Verify that BusLogic_InterruptHandler was called at least TestCount - times. Shared IRQ Channels could cause more than TestCount interrupts to - occur, but there should never be fewer than TestCount, unless one or more - interrupts were lost. - */ - if (FinalInterruptCount < InitialInterruptCount + TestCount) - return BusLogic_Failure(HostAdapter, "HOST ADAPTER INTERRUPT TEST"); - /* - Indicate the Host Adapter Interrupt Test completed successfully. - */ - return true; -} - - -/* BusLogic_InitializeHostAdapter initializes Host Adapter. This is the only function called during SCSI Host Adapter detection which modifies the state of the Host Adapter from its initial power on or hard reset state. @@ -2377,20 +2361,31 @@ for each Target Device. */ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - memset(HostAdapter->TaggedQueuingActive, false, - sizeof(HostAdapter->TaggedQueuingActive)); - memset(HostAdapter->CommandSuccessfulFlag, false, - sizeof(HostAdapter->CommandSuccessfulFlag)); - memset(HostAdapter->ActiveCommands, 0, - sizeof(HostAdapter->ActiveCommands)); - memset(HostAdapter->CommandsSinceReset, 0, - sizeof(HostAdapter->CommandsSinceReset)); + { + HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; + HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; + HostAdapter->ActiveCommands[TargetID] = 0; + HostAdapter->CommandsSinceReset[TargetID] = 0; + } /* FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done; /* + Initialize the Outgoing and Incoming Mailbox pointers. + */ + HostAdapter->FirstOutgoingMailbox = + (BusLogic_OutgoingMailbox_T *) HostAdapter->MailboxSpace; + HostAdapter->LastOutgoingMailbox = + HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; + HostAdapter->FirstIncomingMailbox = + (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1); + HostAdapter->LastIncomingMailbox = + HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; + /* Initialize the Outgoing and Incoming Mailbox structures. */ memset(HostAdapter->FirstOutgoingMailbox, 0, @@ -2398,11 +2393,6 @@ memset(HostAdapter->FirstIncomingMailbox, 0, HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T)); /* - Initialize the pointers to the Next Mailboxes. - */ - HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - /* Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. */ ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; @@ -2443,11 +2433,14 @@ Announce Successful Initialization. */ Done: - if (HostAdapter->HostAdapterInitialized) - BusLogic_Warning("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); - else BusLogic_Info("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); + if (!HostAdapter->HostAdapterInitialized) + { + BusLogic_Info("*** %s Initialized Successfully ***\n", + HostAdapter, HostAdapter->FullModelName); + BusLogic_Info("\n", HostAdapter); + } + else BusLogic_Warning("*** %s Initialized Successfully ***\n", + HostAdapter, HostAdapter->FullModelName); HostAdapter->HostAdapterInitialized = true; /* Indicate the Host Adapter Initialization completed successfully. @@ -2458,7 +2451,7 @@ /* BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible - through Host Adapter and reports on the results. + through Host Adapter. */ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T @@ -2469,7 +2462,7 @@ BusLogic_SetupInformation_T SetupInformation; BusLogic_SynchronousPeriod_T SynchronousPeriod; BusLogic_RequestedReplyLength_T RequestedReplyLength; - int TargetDevicesFound = 0, TargetID; + int TargetID; /* Wait a few seconds between the Host Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get @@ -2481,13 +2474,11 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; /* - Inhibit the Target Devices Inquiry if requested. + Inhibit the Target Device Inquiry if requested. */ - if (HostAdapter->LocalOptions.Bits.InhibitTargetInquiry) - { - BusLogic_Info(" Target Device Inquiry Inhibited\n", HostAdapter); - return true; - } + if (HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) + return true; /* Issue the Inquire Target Devices command for host adapters with firmware version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command @@ -2503,6 +2494,9 @@ &InstalledDevices, sizeof(InstalledDevices)) != sizeof(InstalledDevices)) return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].TargetExists = + (InstalledDevices & (1 << TargetID) ? true : false); } else { @@ -2512,10 +2506,9 @@ != sizeof(InstalledDevicesID0to7)) return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7"); - InstalledDevices = 0; for (TargetID = 0; TargetID < 8; TargetID++) - if (InstalledDevicesID0to7[TargetID] != 0) - InstalledDevices |= (1 << TargetID); + HostAdapter->TargetFlags[TargetID].TargetExists = + (InstalledDevicesID0to7[TargetID] != 0 ? true : false); } /* Issue the Inquire Setup Information command. @@ -2526,6 +2519,19 @@ &SetupInformation, sizeof(SetupInformation)) != sizeof(SetupInformation)) return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousOffset[TargetID] = + (TargetID < 8 + ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset + : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset); + if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].WideTransfersActive = + (TargetID < 8 + ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) + ? true : false) + : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8)) + ? true : false)); /* Issue the Inquire Synchronous Period command. */ @@ -2537,69 +2543,96 @@ &SynchronousPeriod, sizeof(SynchronousPeriod)) != sizeof(SynchronousPeriod)) return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; } else for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) - SynchronousPeriod[TargetID] = + HostAdapter->SynchronousPeriod[TargetID] = 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] .TransferPeriod; - else SynchronousPeriod[TargetID] = 0; /* - Save the Installed Devices, Synchronous Values, and Synchronous Period - information in the Host Adapter structure. + Indicate the Target Device Inquiry completed successfully. + */ + return true; +} + + +/* + BusLogic_ReportTargetDeviceInfo reports about the Target Devices accessible + through Host Adapter. +*/ + +static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T + *HostAdapter) +{ + int TargetID; + /* + Inhibit the Target Device Inquiry and Reporting if requested. */ - HostAdapter->InstalledDevices = InstalledDevices; - memcpy(HostAdapter->SynchronousValues, - SetupInformation.SynchronousValuesID0to7, - sizeof(BusLogic_SynchronousValues8_T)); - if (HostAdapter->HostWideSCSI) - memcpy(&HostAdapter->SynchronousValues[8], - SetupInformation.SynchronousValuesID8to15, - sizeof(BusLogic_SynchronousValues8_T)); - memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod, - sizeof(BusLogic_SynchronousPeriod_T)); + if (BusLogic_MultiMasterHostAdapterP(HostAdapter) && + HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) + return; /* Report on the Target Devices found. */ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->InstalledDevices & (1 << TargetID)) - { - int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID]; - if (SynchronousPeriod > 10) - { - int SynchronousTransferRate = 100000000 / SynchronousPeriod; - int RoundedSynchronousTransferRate = - (SynchronousTransferRate + 5000) / 10000; - BusLogic_Info(" Target %d: Synchronous at " - "%d.%02d mega-transfers/second, offset %d\n", - HostAdapter, TargetID, - RoundedSynchronousTransferRate / 100, - RoundedSynchronousTransferRate % 100, - HostAdapter->SynchronousValues[TargetID].Offset); - } - else if (SynchronousPeriod > 0) - { - int SynchronousTransferRate = 100000000 / SynchronousPeriod; - int RoundedSynchronousTransferRate = - (SynchronousTransferRate + 50000) / 100000; - BusLogic_Info(" Target %d: Synchronous at " - "%d.%01d mega-transfers/second, offset %d\n", - HostAdapter, TargetID, - RoundedSynchronousTransferRate / 10, - RoundedSynchronousTransferRate % 10, - HostAdapter->SynchronousValues[TargetID].Offset); - } - else BusLogic_Info(" Target %d: Asynchronous\n", - HostAdapter, TargetID); - TargetDevicesFound++; - } - if (TargetDevicesFound == 0) - BusLogic_Info(" No Target Devices Found\n", HostAdapter); - /* - Indicate the Target Device Inquiry completed successfully. - */ - return true; + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported) + { + int SynchronousTransferRate = 0; + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + { + boolean WideTransfersActive; + FlashPoint_InquireTargetInfo( + HostAdapter->CardHandle, TargetID, + &HostAdapter->SynchronousPeriod[TargetID], + &HostAdapter->SynchronousOffset[TargetID], + &WideTransfersActive); + TargetFlags->WideTransfersActive = WideTransfersActive; + } + else if (TargetFlags->WideTransfersSupported && + (HostAdapter->WidePermitted & (1 << TargetID)) && + strcmp(HostAdapter->FirmwareVersion, "5.06L") < 0) + TargetFlags->WideTransfersActive = true; + if (HostAdapter->SynchronousPeriod[TargetID] > 0) + SynchronousTransferRate = + 100000 / HostAdapter->SynchronousPeriod[TargetID]; + if (TargetFlags->WideTransfersActive) + SynchronousTransferRate <<= 1; + if (SynchronousTransferRate >= 9950) + { + SynchronousTransferRate = (SynchronousTransferRate + 50) / 100; + BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at " + "%d.%01d MB/sec, offset %d\n", + HostAdapter, TargetID, + HostAdapter->QueueDepth[TargetID], + (TargetFlags->WideTransfersActive ? "Wide " : ""), + SynchronousTransferRate / 10, + SynchronousTransferRate % 10, + HostAdapter->SynchronousOffset[TargetID]); + } + else if (SynchronousTransferRate > 0) + { + SynchronousTransferRate = (SynchronousTransferRate + 5) / 10; + BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at " + "%d.%02d MB/sec, offset %d\n", + HostAdapter, TargetID, + HostAdapter->QueueDepth[TargetID], + (TargetFlags->WideTransfersActive ? "Wide " : ""), + SynchronousTransferRate / 100, + SynchronousTransferRate % 100, + HostAdapter->SynchronousOffset[TargetID]); + } + else BusLogic_Info("Target %d: Queue Depth %d, Asynchronous\n", + HostAdapter, TargetID, + HostAdapter->QueueDepth[TargetID]); + TargetFlags->TargetInfoReported = true; + } + } } @@ -2629,9 +2662,11 @@ /* - BusLogic_SelectQueueDepths selects Queue Depths for each Target Device - based on the Host Adapter's Total Queue Depth and the number, type, speed, - and capabilities of the Target Devices. + BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based + on the Host Adapter's Total Queue Depth and the number, type, speed, and + capabilities of the Target Devices. When called for the last Host Adapter, + it reports on the Target Device Information for all BusLogic Host Adapters + since all the Target Devices have now been probed. */ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host, @@ -2639,41 +2674,60 @@ { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; - int TaggedQueueDepth = HostAdapter->TaggedQueueDepth; - int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth; - int TaggedDeviceCount = 0, UntaggedDeviceCount = 0; - int DesiredCCBs = HostAdapter->MaxTargetDevices - 1; + int TaggedDeviceCount = 0, AutomaticTaggedDeviceCount = 0; + int UntaggedDeviceCount = 0, AutomaticTaggedQueueDepth = 0; + int AllocatedQueueDepth = 0; SCSI_Device_T *Device; - for (Device = DeviceList; Device != NULL; Device = Device->next) - if (Device->host == Host) + int TargetID; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists) { - if (Device->tagged_supported && - (HostAdapter->TaggedQueuingPermitted & (1 << Device->id))) - TaggedDeviceCount++; + int QueueDepth = HostAdapter->UntaggedQueueDepth; + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && + (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) + { + QueueDepth = HostAdapter->QueueDepth[TargetID]; + TaggedDeviceCount++; + if (QueueDepth == 0) AutomaticTaggedDeviceCount++; + } else UntaggedDeviceCount++; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + AllocatedQueueDepth += QueueDepth; } - if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0) + HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount; + if (AutomaticTaggedDeviceCount > 0) { - TaggedQueueDepth = - 1 + ((HostAdapter->HostAdapterQueueDepth - - UntaggedDeviceCount * UntaggedQueueDepth) - / TaggedDeviceCount); - if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth) - TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth; - } - for (Device = DeviceList; Device != NULL; Device = Device->next) + AutomaticTaggedQueueDepth = + (HostAdapter->HostAdapterQueueDepth - AllocatedQueueDepth) + / AutomaticTaggedDeviceCount; + if (AutomaticTaggedQueueDepth > BusLogic_MaxAutomaticTaggedQueueDepth) + AutomaticTaggedQueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; + if (AutomaticTaggedQueueDepth < BusLogic_MinAutomaticTaggedQueueDepth) + AutomaticTaggedQueueDepth = BusLogic_MinAutomaticTaggedQueueDepth; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists && + HostAdapter->QueueDepth[TargetID] == 0) + { + AllocatedQueueDepth += AutomaticTaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = AutomaticTaggedQueueDepth; + } + } + for (Device = DeviceList; Device != NULL; Device = Device->next) if (Device->host == Host) - { - if (Device->tagged_supported && - (HostAdapter->TaggedQueuingPermitted & (1 << Device->id))) - Device->queue_depth = TaggedQueueDepth; - else Device->queue_depth = UntaggedQueueDepth; - HostAdapter->QueueDepth[Device->id] = Device->queue_depth; - DesiredCCBs += Device->queue_depth; - } + Device->queue_depth = HostAdapter->QueueDepth[Device->id]; + /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */ + AllocatedQueueDepth += HostAdapter->TargetDeviceCount; + if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth) + AllocatedQueueDepth = HostAdapter->DriverQueueDepth; BusLogic_CreateAdditionalCCBs(HostAdapter, - DesiredCCBs - HostAdapter->AllocatedCCBs, + AllocatedQueueDepth + - HostAdapter->AllocatedCCBs, false); + if (HostAdapter == BusLogic_LastRegisteredHostAdapter) + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; + HostAdapter != NULL; + HostAdapter = HostAdapter->NextAll) + BusLogic_ReportTargetDeviceInfo(HostAdapter); } @@ -2687,50 +2741,48 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate) { - int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0, ProbeIndex; - char *MessageBuffer = NULL; - if (BusLogic_ProbeOptions.Bits.NoProbe) return 0; - BusLogic_InitializeProbeInfoList(); + int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; + BusLogic_HostAdapter_T *PrototypeHostAdapter; + if (BusLogic_ProbeOptions.NoProbe) return 0; + BusLogic_ProbeInfoList = (BusLogic_ProbeInfo_T *) + kmalloc(BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T), + GFP_ATOMIC); + if (BusLogic_ProbeInfoList == NULL) + { + BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); + return 0; + } + memset(BusLogic_ProbeInfoList, 0, + BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T)); + PrototypeHostAdapter = (BusLogic_HostAdapter_T *) + kmalloc(sizeof(BusLogic_HostAdapter_T), GFP_ATOMIC); + if (PrototypeHostAdapter == NULL) + { + kfree(BusLogic_ProbeInfoList); + BusLogic_Error("BusLogic: Unable to allocate Prototype " + "Host Adapter\n", NULL); + return 0; + } + memset(PrototypeHostAdapter, 0, sizeof(BusLogic_HostAdapter_T)); + if (BusLogic_Options != NULL) + BusLogic_ParseDriverOptions(BusLogic_Options); + BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; + BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; SCSI_Host_T *Host; if (ProbeInfo->IO_Address == 0) continue; memset(HostAdapter, 0, sizeof(BusLogic_HostAdapter_T)); - HostAdapter->IO_Address = ProbeInfo->IO_Address; - HostAdapter->PCI_Address = ProbeInfo->PCI_Address; HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; + HostAdapter->IO_Address = ProbeInfo->IO_Address; + HostAdapter->PCI_Address = ProbeInfo->PCI_Address; HostAdapter->Bus = ProbeInfo->Bus; HostAdapter->Device = ProbeInfo->Device; HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; HostAdapter->AddressCount = - BusLogic_HostAdapter_AddressCount[HostAdapter->HostAdapterType]; - if (MessageBuffer == NULL) - MessageBuffer = - scsi_init_malloc(BusLogic_MessageBufferSize, GFP_ATOMIC); - if (MessageBuffer == NULL) - { - BusLogic_Error("BusLogic: Unable to allocate Message Buffer\n", - HostAdapter); - return BusLogicHostAdapterCount; - } - HostAdapter->MessageBuffer = MessageBuffer; - /* - If an explicit I/O Address was specified, Initialize the Command Line - Entry field and inhibit the check for whether the I/O Address range is - already in use. - */ - if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount && - BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == - HostAdapter->IO_Address) - HostAdapter->CommandLineEntry = - &BusLogic_CommandLineEntries[CommandLineEntryIndex++]; - else if (check_region(HostAdapter->IO_Address, - HostAdapter->AddressCount) < 0) - continue; + BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; /* Probe the Host Adapter. If unsuccessful, abort further initialization. */ @@ -2739,22 +2791,20 @@ Hard Reset the Host Adapter. If unsuccessful, abort further initialization. */ - if (!BusLogic_HardResetHostAdapter(HostAdapter)) continue; + if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue; /* Check the Host Adapter. If unsuccessful, abort further initialization. */ if (!BusLogic_CheckHostAdapter(HostAdapter)) continue; /* - Initialize the Command Line Entry field if an explicit I/O Address - was not specified. + Initialize the Driver Options field if provided. */ - if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount && - BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == 0) - HostAdapter->CommandLineEntry = - &BusLogic_CommandLineEntries[CommandLineEntryIndex++]; + if (DriverOptionsIndex < BusLogic_DriverOptionsCount) + HostAdapter->DriverOptions = + &BusLogic_DriverOptions[DriverOptionsIndex++]; /* Announce the Driver Version and Date, Author's Name, Copyright Notice, - and Contact Address. + and Electronic Mail Address. */ BusLogic_AnnounceDriver(HostAdapter); /* @@ -2772,8 +2822,7 @@ */ Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T)); HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; - memcpy(HostAdapter, &HostAdapterPrototype, - sizeof(BusLogic_HostAdapter_T)); + memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T)); HostAdapter->SCSI_Host = Host; HostAdapter->HostNumber = Host->host_no; Host->select_queue_depths = BusLogic_SelectQueueDepths; @@ -2786,18 +2835,14 @@ BusLogic_RegisterHostAdapter(HostAdapter); /* Read the Host Adapter Configuration, Configure the Host Adapter, - Acquire the System Resources necessary to use the Host Adapter, - then Test Interrupts, Create the Mailboxes, Initial CCBs, and - Target Device Statistics, Initialize the Host Adapter, and - finally perform Target Device Inquiry. + Acquire the System Resources necessary to use the Host Adapter, then + Create the Initial CCBs, Initialize the Host Adapter, and finally + perform Target Device Inquiry. */ if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && - BusLogic_TestInterrupts(HostAdapter) && - BusLogic_CreateMailboxes(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && - BusLogic_CreateTargetDeviceStatistics(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) { @@ -2807,7 +2852,6 @@ Name of the Host Adapter will appear, and initialize the SCSI Host structure. */ - MessageBuffer = NULL; release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); request_region(HostAdapter->IO_Address, @@ -2819,24 +2863,22 @@ else { /* - An error occurred during Host Adapter Configuration Querying, - Host Adapter Configuration, Resource Acquisition, Interrupt - Testing, CCB Creation, Host Adapter Initialization, or Target - Device Inquiry, so remove Host Adapter from the list of - registered BusLogic Host Adapters, destroy the Target Device - Statistics, CCBs, and Mailboxes, Release the System Resources, - and Unregister the SCSI Host. + An error occurred during Host Adapter Configuration Querying, Host + Adapter Configuration, Resource Acquisition, CCB Creation, Host + Adapter Initialization, or Target Device Inquiry, so remove Host + Adapter from the list of registered BusLogic Host Adapters, destroy + the CCBs, Release the System Resources, and Unregister the SCSI + Host. */ - BusLogic_DestroyTargetDeviceStatistics(HostAdapter); BusLogic_DestroyCCBs(HostAdapter); - BusLogic_DestroyMailboxes(HostAdapter); BusLogic_ReleaseResources(HostAdapter); BusLogic_UnregisterHostAdapter(HostAdapter); scsi_unregister(Host); } } - if (MessageBuffer != NULL) - scsi_init_free(MessageBuffer, BusLogic_MessageBufferSize); + kfree(PrototypeHostAdapter); + kfree(BusLogic_ProbeInfoList); + BusLogic_ProbeInfoList = NULL; return BusLogicHostAdapterCount; } @@ -2852,21 +2894,16 @@ BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; /* - FlashPoint Host Adapters must also be released by the FlashPoint + FlashPoint Host Adapters must first be released by the FlashPoint SCCB Manager. */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); - scsi_init_free((char *) HostAdapter->FlashPointInfo, - sizeof(FlashPoint_Info_T)); - } + FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); /* - Destroy the CCBs and Mailboxes, and release any system resources acquired - to support Host Adapter. + Destroy the CCBs and release any system resources acquired to + support Host Adapter. */ BusLogic_DestroyCCBs(HostAdapter); - BusLogic_DestroyMailboxes(HostAdapter); BusLogic_ReleaseResources(HostAdapter); /* Release usage of the I/O Address range. @@ -2989,27 +3026,29 @@ BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) Bus_to_Virtual(NextIncomingMailbox->CCB); if (CompletionCode != BusLogic_AbortedCommandNotFound) - if (CCB->Status == BusLogic_CCB_Active || - CCB->Status == BusLogic_CCB_Reset) - { - /* - Save the Completion Code for this CCB and queue the CCB - for completion processing. - */ - CCB->CompletionCode = CompletionCode; - BusLogic_QueueCompletedCCB(CCB); - } - else - { - /* - If a CCB ever appears in an Incoming Mailbox and is not marked as - status Active or Reset, then there is most likely a bug in the - Host Adapter firmware. - */ - BusLogic_Warning("Illegal CCB #%ld status %d in " - "Incoming Mailbox\n", HostAdapter, - CCB->SerialNumber, CCB->Status); - } + { + if (CCB->Status == BusLogic_CCB_Active || + CCB->Status == BusLogic_CCB_Reset) + { + /* + Save the Completion Code for this CCB and queue the CCB + for completion processing. + */ + CCB->CompletionCode = CompletionCode; + BusLogic_QueueCompletedCCB(CCB); + } + else + { + /* + If a CCB ever appears in an Incoming Mailbox and is not marked + as status Active or Reset, then there is most likely a bug in + the Host Adapter firmware. + */ + BusLogic_Warning("Illegal CCB #%ld status %d in " + "Incoming Mailbox\n", HostAdapter, + CCB->SerialNumber, CCB->Status); + } + } NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; @@ -3048,10 +3087,9 @@ "%d Completed\n", HostAdapter, CCB->SerialNumber, TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID] - .BusDeviceResetsCompleted); + &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; HostAdapter->CommandsSinceReset[TargetID] = 0; - HostAdapter->TaggedQueuingActive[TargetID] = false; HostAdapter->LastResetCompleted[TargetID] = jiffies; /* Place CCB back on the Host Adapter's free list. @@ -3102,16 +3140,17 @@ HostAdapter, CCB->SerialNumber, CCB->TargetID); break; case BusLogic_CommandCompletedWithoutError: - HostAdapter->TargetDeviceStatistics[CCB->TargetID] + HostAdapter->TargetStatistics[CCB->TargetID] .CommandsCompleted++; - HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true; + HostAdapter->TargetFlags[CCB->TargetID] + .CommandSuccessfulFlag = true; Command->result = DID_OK << 16; break; case BusLogic_CommandAbortedAtHostRequest: BusLogic_Warning("CCB #%ld to Target %d Aborted\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[CCB->TargetID] + &HostAdapter->TargetStatistics[CCB->TargetID] .CommandAbortsCompleted); Command->result = DID_ABORT << 16; break; @@ -3122,9 +3161,9 @@ CCB->TargetDeviceStatus); if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) { - HostAdapter->TargetDeviceStatistics[CCB->TargetID] + HostAdapter->TargetStatistics[CCB->TargetID] .CommandsCompleted++; - if (BusLogic_GlobalOptions.Bits.TraceErrors) + if (BusLogic_GlobalOptions.TraceErrors) { int i; BusLogic_Notice("CCB #%ld Target %d: Result %X Host " @@ -3148,6 +3187,22 @@ break; } /* + When an INQUIRY command completes normally, save the + CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit + Wide Data Transfers Supported) bits. + */ + if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && + CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) + { + BusLogic_TargetFlags_T *TargetFlags = + &HostAdapter->TargetFlags[CCB->TargetID]; + SCSI_Inquiry_T *InquiryResult = + (SCSI_Inquiry_T *) Command->request_buffer; + TargetFlags->TargetExists = true; + TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; + TargetFlags->WideTransfersSupported = InquiryResult->WBus16; + } + /* Place CCB back on the Host Adapter's free list. */ BusLogic_DeallocateCCB(CCB); @@ -3172,7 +3227,7 @@ { BusLogic_HostAdapter_T *FirstHostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel]; - boolean HostAdapterResetRequested = false; + boolean HostAdapterResetRequired = false; BusLogic_HostAdapter_T *HostAdapter; BusLogic_Lock_T Lock; /* @@ -3214,8 +3269,8 @@ */ if (InterruptRegister.Bits.ExternalBusReset) { - HostAdapter->HostAdapterResetRequested = true; - HostAdapterResetRequested = true; + HostAdapter->HostAdapterExternalReset = true; + HostAdapterResetRequired = true; } else if (InterruptRegister.Bits.IncomingMailboxLoaded) BusLogic_ScanIncomingMailboxes(HostAdapter); @@ -3229,11 +3284,20 @@ Check if there is a pending interrupt for this Host Adapter. */ if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) - if (FlashPoint_HandleInterrupt(HostAdapter->CardHandle) - == FlashPoint_ExternalBusReset) + switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) { - HostAdapter->HostAdapterResetRequested = true; - HostAdapterResetRequested = true; + case FlashPoint_NormalInterrupt: + break; + case FlashPoint_ExternalBusReset: + HostAdapter->HostAdapterExternalReset = true; + HostAdapterResetRequired = true; + break; + case FlashPoint_InternalError: + BusLogic_Warning("Internal FlashPoint Error detected" + " - Resetting Host Adapter\n", HostAdapter); + HostAdapter->HostAdapterInternalError = true; + HostAdapterResetRequired = true; + break; } } /* @@ -3250,14 +3314,16 @@ Iterate over the Host Adapters performing any requested Host Adapter Resets. */ - if (HostAdapterResetRequested) + if (HostAdapterResetRequired) for (HostAdapter = FirstHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) - if (HostAdapter->HostAdapterResetRequested) + if (HostAdapter->HostAdapterExternalReset || + HostAdapter->HostAdapterInternalError) { BusLogic_ResetHostAdapter(HostAdapter, NULL, 0); - HostAdapter->HostAdapterResetRequested = false; + HostAdapter->HostAdapterExternalReset = false; + HostAdapter->HostAdapterInternalError = false; scsi_mark_host_reset(HostAdapter->SCSI_Host); } } @@ -3294,8 +3360,7 @@ { HostAdapter->ActiveCommands[CCB->TargetID]++; if (CCB->Opcode != BusLogic_BusDeviceReset) - HostAdapter->TargetDeviceStatistics[CCB->TargetID] - .CommandsAttempted++; + HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; } return true; } @@ -3313,8 +3378,10 @@ { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Command->host->hostdata; - BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics = - HostAdapter->TargetDeviceStatistics; + BusLogic_TargetFlags_T *TargetFlags = + &HostAdapter->TargetFlags[Command->target]; + BusLogic_TargetStatistics_T *TargetStatistics = + HostAdapter->TargetStatistics; unsigned char *CDB = Command->cmnd; int CDB_Length = Command->cmd_len; int TargetID = Command->target; @@ -3372,13 +3439,9 @@ int Segment; CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T); -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList); - else CCB->DataPointer = (BusLogic_BusAddress_T) CCB->ScatterGatherList; -#else - CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList); -#endif + else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); for (Segment = 0; Segment < SegmentCount; Segment++) { CCB->ScatterGatherList[Segment].SegmentByteCount = @@ -3392,22 +3455,20 @@ case READ_6: case READ_10: CCB->DataDirection = BusLogic_DataInLengthChecked; - TargetDeviceStatistics[TargetID].ReadCommands++; + TargetStatistics[TargetID].ReadCommands++; BusLogic_IncrementByteCounter( - &TargetDeviceStatistics[TargetID].TotalBytesRead, BufferLength); + &TargetStatistics[TargetID].TotalBytesRead, BufferLength); BusLogic_IncrementSizeBucket( - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets, - BufferLength); + TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); break; case WRITE_6: case WRITE_10: CCB->DataDirection = BusLogic_DataOutLengthChecked; - TargetDeviceStatistics[TargetID].WriteCommands++; + TargetStatistics[TargetID].WriteCommands++; BusLogic_IncrementByteCounter( - &TargetDeviceStatistics[TargetID].TotalBytesWritten, BufferLength); + &TargetStatistics[TargetID].TotalBytesWritten, BufferLength); BusLogic_IncrementSizeBucket( - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets, - BufferLength); + TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); break; default: CCB->DataDirection = BusLogic_UncheckedDataTransfer; @@ -3435,20 +3496,18 @@ necessary to wait until there are no pending commands for a target device before queuing tagged commands. */ - HostAdapter->TaggedQueuingSupported[TargetID] = - Command->device->tagged_supported; if (HostAdapter->CommandsSinceReset[TargetID]++ >= BusLogic_MaxTaggedQueueDepth && - !HostAdapter->TaggedQueuingActive[TargetID] && + !TargetFlags->TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] == 0 && - HostAdapter->TaggedQueuingSupported[TargetID] && + TargetFlags->TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { - HostAdapter->TaggedQueuingActive[TargetID] = true; + TargetFlags->TaggedQueuingActive = true; BusLogic_Notice("Tagged Queuing now active for Target %d\n", HostAdapter, TargetID); } - if (HostAdapter->TaggedQueuingActive[TargetID]) + if (TargetFlags->TaggedQueuingActive) { BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag; /* @@ -3458,7 +3517,7 @@ write nearer the head position continue to arrive without interruption. Therefore, for each Target Device this driver keeps track of the last time either the queue was empty or an Ordered Queue Tag was issued. If - more than 3 seconds (one fifth of the 15 second disk timeout) have + more than 4 seconds (one fifth of the 20 second disk timeout) have elapsed since this last sequence point, this command will be issued with an Ordered Queue Tag rather than a Simple Queue Tag, which forces the Target Device to complete all previously queued commands before @@ -3466,7 +3525,7 @@ */ if (HostAdapter->ActiveCommands[TargetID] == 0) HostAdapter->LastSequencePoint[TargetID] = jiffies; - else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 3*HZ) + else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ) { HostAdapter->LastSequencePoint[TargetID] = jiffies; QueueTag = BusLogic_OrderedQueueTag; @@ -3520,7 +3579,7 @@ */ CCB->Status = BusLogic_CCB_Active; HostAdapter->ActiveCommands[TargetID]++; - TargetDeviceStatistics[TargetID].CommandsAttempted++; + TargetStatistics[TargetID].CommandsAttempted++; FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); /* The Command may have already completed and BusLogic_QueueCompletedCCB @@ -3551,7 +3610,7 @@ BusLogic_CCB_T *CCB; int Result; BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsRequested); + &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); /* Acquire exclusive access to Host Adapter. */ @@ -3605,7 +3664,7 @@ Firmware version 5.xx does generate Abort Tag messages, so it is possible to abort commands when Tagged Queuing is active. */ - if (HostAdapter->TaggedQueuingActive[TargetID] && + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->FirmwareVersion[0] < '5') { BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " @@ -3619,8 +3678,7 @@ BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID] - .CommandAbortsAttempted); + &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); Result = SCSI_ABORT_PENDING; } else @@ -3639,7 +3697,7 @@ BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsAttempted); + &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); /* The Abort may have already been completed and @@ -3674,11 +3732,24 @@ BusLogic_Lock_T Lock; BusLogic_CCB_T *CCB; int TargetID, Result; - if (Command == NULL) - BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); - else BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[Command->target] - .HostAdapterResetsRequested); + boolean HardReset; + if (HostAdapter->HostAdapterExternalReset) + { + BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); + HardReset = false; + } + else if (HostAdapter->HostAdapterInternalError) + { + BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); + HardReset = true; + } + else + { + BusLogic_IncrementErrorCounter( + &HostAdapter->TargetStatistics[Command->target] + .HostAdapterResetsRequested); + HardReset = true; + } /* Acquire exclusive access to Host Adapter. */ @@ -3724,20 +3795,25 @@ } } if (Command == NULL) - BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", - HostAdapter, HostAdapter->FullModelName); + { + if (HostAdapter->HostAdapterInternalError) + BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", + HostAdapter, HostAdapter->FullModelName); + else BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", + HostAdapter, HostAdapter->FullModelName); + } else { BusLogic_Warning("Resetting %s due to Target %d\n", HostAdapter, HostAdapter->FullModelName, Command->target); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[Command->target] + &HostAdapter->TargetStatistics[Command->target] .HostAdapterResetsAttempted); } /* Attempt to Reset and Reinitialize the Host Adapter. */ - if (!(BusLogic_HardResetHostAdapter(HostAdapter) && + if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && BusLogic_InitializeHostAdapter(HostAdapter))) { BusLogic_Error("Resetting %s Failed\n", HostAdapter, @@ -3747,7 +3823,7 @@ } if (Command != NULL) BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[Command->target] + &HostAdapter->TargetStatistics[Command->target] .HostAdapterResetsCompleted); /* Mark all currently executing CCBs as having been Reset. @@ -3762,7 +3838,8 @@ Note that a timer interrupt may occur here, but all active CCBs have already been marked Reset and so a reentrant call will return Pending. */ - BusLogic_Delay(HostAdapter->BusSettleTime); + if (HardReset) + BusLogic_Delay(HostAdapter->BusSettleTime); /* If this is a Synchronous Reset, perform completion processing for the Command being Reset. @@ -3818,7 +3895,7 @@ BusLogic_Lock_T Lock; int Result = -1; BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsRequested); + &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested); /* Acquire exclusive access to Host Adapter. */ @@ -3892,7 +3969,7 @@ while there are tagged commands outstanding. Therefore, in that case a full Host Adapter Hard Reset and SCSI Bus Reset must be done. */ - if (HostAdapter->TaggedQueuingActive[TargetID] && + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] > 0 && HostAdapter->FirmwareVersion[0] < '5') goto Done; @@ -3959,7 +4036,7 @@ processing performed. */ BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted); + &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsAttempted); HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB; HostAdapter->LastResetAttempted[TargetID] = jiffies; for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll) @@ -4008,11 +4085,11 @@ it has been less than 10 minutes since the last reset occurred, or since the system was initialized if no prior resets have occurred. */ - if (HostAdapter->TaggedQueuingActive[TargetID] && + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && jiffies - HostAdapter->LastResetCompleted[TargetID] < 10*60*HZ) { HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); - HostAdapter->TaggedQueuingActive[TargetID] = false; + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; BusLogic_Warning("Tagged Queuing now disabled for Target %d\n", HostAdapter, TargetID); } @@ -4033,10 +4110,10 @@ forcing a Hard Reset before the Bus Device Reset has had a chance to clear the error condition. */ - if (HostAdapter->CommandSuccessfulFlag[TargetID] || + if (HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag || jiffies - HostAdapter->LastResetAttempted[TargetID] < HZ/10) { - HostAdapter->CommandSuccessfulFlag[TargetID] = false; + HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags); } /* Fall through to Hard Reset case. */ @@ -4077,16 +4154,18 @@ struct buffer_head *BufferHead; if (HostAdapter->ExtendedTranslationEnabled && Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */) - if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - } - else - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - } + { + if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) + { + DiskParameters->Heads = 255; + DiskParameters->Sectors = 63; + } + else + { + DiskParameters->Heads = 128; + DiskParameters->Sectors = 32; + } + } else { DiskParameters->Heads = 64; @@ -4106,24 +4185,28 @@ */ if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55) { - struct partition *PartitionEntry = - (struct partition *) (BufferHead->b_data + 0x1BE); + PartitionTable_T *FirstPartitionEntry = + (PartitionTable_T *) (BufferHead->b_data + 0x1BE); + PartitionTable_T *PartitionEntry = FirstPartitionEntry; int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; + unsigned char PartitionEntryEndHead, PartitionEntryEndSector; for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) { - if (PartitionEntry->end_head == 64-1) + PartitionEntryEndHead = PartitionEntry->end_head; + PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; + if (PartitionEntryEndHead == 64-1) { DiskParameters->Heads = 64; DiskParameters->Sectors = 32; break; } - else if (PartitionEntry->end_head == 128-1) + else if (PartitionEntryEndHead == 128-1) { DiskParameters->Heads = 128; DiskParameters->Sectors = 32; break; } - else if (PartitionEntry->end_head == 255-1) + else if (PartitionEntryEndHead == 255-1) { DiskParameters->Heads = 255; DiskParameters->Sectors = 63; @@ -4131,14 +4214,29 @@ } PartitionEntry++; } + if (PartitionNumber == 4) + { + PartitionEntryEndHead = FirstPartitionEntry->end_head; + PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; + } DiskParameters->Cylinders = Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors); - if (SavedCylinders != DiskParameters->Cylinders) + if (PartitionNumber < 4 && + PartitionEntryEndSector == DiskParameters->Sectors) { - BusLogic_Warning("Warning: Extended Translation Setting " - "(> 1GB Switch) does not match\n", HostAdapter); - BusLogic_Warning("Partition Table - Adopting %d/%d Geometry " - "from Partition Table\n", HostAdapter, + if (DiskParameters->Cylinders != SavedCylinders) + BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", + HostAdapter, + DiskParameters->Heads, DiskParameters->Sectors); + } + else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) + { + BusLogic_Warning("Warning: Partition Table appears to " + "have Geometry %d/%d which is\n", HostAdapter, + PartitionEntryEndHead + 1, + PartitionEntryEndSector); + BusLogic_Warning("not compatible with current BusLogic " + "Host Adapter Geometry %d/%d\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); } } @@ -4156,22 +4254,21 @@ int HostNumber, int WriteFlag) { BusLogic_HostAdapter_T *HostAdapter; - BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics; - int IRQ_Channel, TargetID, Length; + BusLogic_TargetStatistics_T *TargetStatistics; + int TargetID, Length; char *Buffer; if (WriteFlag) return 0; - for (IRQ_Channel = 0; IRQ_Channel < NR_IRQS; IRQ_Channel++) + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; + HostAdapter != NULL; + HostAdapter = HostAdapter->NextAll) + if (HostAdapter->HostNumber == HostNumber) break; + if (HostAdapter == NULL) { - HostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel]; - while (HostAdapter != NULL) - { - if (HostAdapter->HostNumber == HostNumber) break; - HostAdapter = HostAdapter->Next; - } - if (HostAdapter != NULL) break; + BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", + NULL, HostNumber); + return 0; } - if (HostAdapter == NULL) return -1; - TargetDeviceStatistics = HostAdapter->TargetDeviceStatistics; + TargetStatistics = HostAdapter->TargetStatistics; Buffer = HostAdapter->MessageBuffer; Length = HostAdapter->MessageBufferLength; Length += sprintf(&Buffer[Length], "\n\ @@ -4182,100 +4279,105 @@ Length += sprintf(&Buffer[Length], "\n\n\ DATA TRANSFER STATISTICS\n\ \n\ -Target Tagged Queuing Queue Depth Commands Attempted Commands Completed\n\ -====== ============== =========== ================== ==================\n"); +Target Tagged Queuing Queue Depth Active Attempted Completed\n\ +====== ============== =========== ====== ========= =========\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { - Length += - sprintf(&Buffer[Length], " %2d %s", TargetID, - (HostAdapter->TaggedQueuingSupported[TargetID] - ? (HostAdapter->TaggedQueuingActive[TargetID] - ? " Active" - : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) - ? " Permitted" : " Disabled")) - : "Not Supported")); - Length += sprintf(&Buffer[Length], - " %3d %9u %9u\n", - HostAdapter->QueueDepth[TargetID], - TargetDeviceStatistics[TargetID].CommandsAttempted, - TargetDeviceStatistics[TargetID].CommandsCompleted); - } + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], " %2d %s", TargetID, + (TargetFlags->TaggedQueuingSupported + ? (TargetFlags->TaggedQueuingActive + ? " Active" + : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) + ? " Permitted" : " Disabled")) + : "Not Supported")); + Length += sprintf(&Buffer[Length], + " %3d %3u %9u %9u\n", + HostAdapter->QueueDepth[TargetID], + HostAdapter->ActiveCommands[TargetID], + TargetStatistics[TargetID].CommandsAttempted, + TargetStatistics[TargetID].CommandsCompleted); + } Length += sprintf(&Buffer[Length], "\n\ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ ====== ============= ============== =================== ===================\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, + TargetStatistics[TargetID].ReadCommands, + TargetStatistics[TargetID].WriteCommands); + if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) Length += - sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, - TargetDeviceStatistics[TargetID].ReadCommands, - TargetDeviceStatistics[TargetID].WriteCommands); - if (TargetDeviceStatistics[TargetID].TotalBytesRead.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u", - TargetDeviceStatistics[TargetID].TotalBytesRead.Billions, - TargetDeviceStatistics[TargetID].TotalBytesRead.Units); - else - Length += - sprintf(&Buffer[Length], " %9u", - TargetDeviceStatistics[TargetID].TotalBytesRead.Units); - if (TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u\n", - TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions, - TargetDeviceStatistics[TargetID].TotalBytesWritten.Units); - else - Length += - sprintf(&Buffer[Length], " %9u\n", - TargetDeviceStatistics[TargetID].TotalBytesWritten.Units); - } + sprintf(&Buffer[Length], " %9u%09u", + TargetStatistics[TargetID].TotalBytesRead.Billions, + TargetStatistics[TargetID].TotalBytesRead.Units); + else + Length += + sprintf(&Buffer[Length], " %9u", + TargetStatistics[TargetID].TotalBytesRead.Units); + if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) + Length += + sprintf(&Buffer[Length], " %9u%09u\n", + TargetStatistics[TargetID].TotalBytesWritten.Billions, + TargetStatistics[TargetID].TotalBytesWritten.Units); + else + Length += + sprintf(&Buffer[Length], " %9u\n", + TargetStatistics[TargetID].TotalBytesWritten.Units); + } Length += sprintf(&Buffer[Length], "\n\ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ ====== ======= ========= ========= ========= ========= =========\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[0], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[1], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[2], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[3], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[4]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[0], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[1], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[2], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[3], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[4]); - } + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[0], + TargetStatistics[TargetID].ReadCommandSizeBuckets[1], + TargetStatistics[TargetID].ReadCommandSizeBuckets[2], + TargetStatistics[TargetID].ReadCommandSizeBuckets[3], + TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[0], + TargetStatistics[TargetID].WriteCommandSizeBuckets[1], + TargetStatistics[TargetID].WriteCommandSizeBuckets[2], + TargetStatistics[TargetID].WriteCommandSizeBuckets[3], + TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); + } Length += sprintf(&Buffer[Length], "\n\ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ ====== ======= ========= ========= ========= ========= =========\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[5], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[6], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[7], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[8], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[9]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[5], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[6], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[7], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[8], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[9]); - } + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[5], + TargetStatistics[TargetID].ReadCommandSizeBuckets[6], + TargetStatistics[TargetID].ReadCommandSizeBuckets[7], + TargetStatistics[TargetID].ReadCommandSizeBuckets[8], + TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[5], + TargetStatistics[TargetID].WriteCommandSizeBuckets[6], + TargetStatistics[TargetID].WriteCommandSizeBuckets[7], + TargetStatistics[TargetID].WriteCommandSizeBuckets[8], + TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); + } Length += sprintf(&Buffer[Length], "\n\n\ ERROR RECOVERY STATISTICS\n\ \n\ @@ -4284,21 +4386,26 @@ ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\ ====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; Length += sprintf(&Buffer[Length], "\ %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, - TargetDeviceStatistics[TargetID].CommandAbortsRequested, - TargetDeviceStatistics[TargetID].CommandAbortsAttempted, - TargetDeviceStatistics[TargetID].CommandAbortsCompleted, - TargetDeviceStatistics[TargetID].BusDeviceResetsRequested, - TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted, - TargetDeviceStatistics[TargetID].BusDeviceResetsCompleted, - TargetDeviceStatistics[TargetID].HostAdapterResetsRequested, - TargetDeviceStatistics[TargetID].HostAdapterResetsAttempted, - TargetDeviceStatistics[TargetID].HostAdapterResetsCompleted); + TargetStatistics[TargetID].CommandAbortsRequested, + TargetStatistics[TargetID].CommandAbortsAttempted, + TargetStatistics[TargetID].CommandAbortsCompleted, + TargetStatistics[TargetID].BusDeviceResetsRequested, + TargetStatistics[TargetID].BusDeviceResetsAttempted, + TargetStatistics[TargetID].BusDeviceResetsCompleted, + TargetStatistics[TargetID].HostAdapterResetsRequested, + TargetStatistics[TargetID].HostAdapterResetsAttempted, + TargetStatistics[TargetID].HostAdapterResetsCompleted); + } Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets); + Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", + HostAdapter->HostAdapterInternalErrors); if (Length >= BusLogic_MessageBufferSize) BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize); @@ -4340,17 +4447,22 @@ Buffer); HostAdapter->MessageBufferLength += Length; if (BeginningOfLine) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); + { + if (Buffer[0] != '\n' || Length > 1) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], + HostAdapter->HostNumber, Buffer); + } else printk("%s", Buffer); } else { if (BeginningOfLine) - if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); - else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + { + if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], + HostAdapter->HostNumber, Buffer); + else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + } else printk("%s", Buffer); } BeginningOfLine = (Buffer[Length-1] == '\n'); @@ -4358,364 +4470,548 @@ /* - BusLogic_Setup handles processing of Kernel Command Line Arguments. + BusLogic_ParseKeyword parses an individual option keyword. It returns true + and updates the pointer if the keyword is recognized and false otherwise. +*/ - For the BusLogic driver, a Kernel Command Line Entry comprises the driver - identifier "BusLogic=" optionally followed by a comma-separated sequence of - integers and then optionally followed by a comma-separated sequence of - strings. Each command line entry applies to one BusLogic Host Adapter. - Multiple command line entries may be used in systems which contain multiple - BusLogic Host Adapters. +static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword) +{ + char *Pointer = *StringPointer; + while (*Keyword != '\0') + { + char StringChar = *Pointer++; + char KeywordChar = *Keyword++; + if (StringChar >= 'A' && StringChar <= 'Z') + StringChar += 'a' - 'Z'; + if (KeywordChar >= 'A' && KeywordChar <= 'Z') + KeywordChar += 'a' - 'Z'; + if (StringChar != KeywordChar) return false; + } + *StringPointer = Pointer; + return true; +} - The first integer specified is the I/O Address at which the Host Adapter is - located. If unspecified, it defaults to 0 which means to apply this entry to - the first BusLogic Host Adapter found during the default probe sequence. If - any I/O Address parameters are provided on the command line, then the default - probe sequence is omitted. - - The second integer specified is the Tagged Queue Depth to use for Target - Devices that support Tagged Queuing. The Queue Depth is the number of SCSI - commands that are allowed to be concurrently presented for execution. If - unspecified, it defaults to 0 which means to use a value determined - automatically based on the Host Adapter's Total Queue Depth and the number, - type, speed, and capabilities of the detected Target Devices. For Host - Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is - automatically set to BusLogic_TaggedQueueDepthBounceBuffers to avoid - excessive preallocation of DMA Bounce Buffer memory. Target Devices that do - not support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth. - - The third integer specified is the Bus Settle Time in seconds. This is - the amount of time to wait between a Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI Commands. If unspecified, it defaults - to 0 which means to use the value of BusLogic_DefaultBusSettleTime. - - The fourth integer specified is the Local Options. If unspecified, it - defaults to 0. Note that Local Options are only applied to a specific Host - Adapter. - The fifth integer specified is the Global Options. If unspecified, it - defaults to 0. Note that Global Options are applied across all Host - Adapters. +/* + BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options + specifications. - The string options are used to provide control over Tagged Queuing, Error - Recovery, and Host Adapter Probing. + BusLogic Driver Options may be specified either via the Linux Kernel Command + Line or via the Loadable Kernel Module Installation Facility. Driver Options + for multiple host adapters may be specified either by separating the option + strings by a semicolon, or by specifying multiple "BusLogic=" strings on the + command line. Individual option specifications for a single host adapter are + separated by commas. The Probing and Debugging Options apply to all host + adapters whereas the remaining options apply individually only to the + selected host adapter. - The Tagged Queuing specification begins with "TQ:" and allows for explicitly - specifying whether Tagged Queuing is permitted on Target Devices that support - it. The following specification options are available: - - TQ:Default Tagged Queuing will be permitted based on the firmware - version of the BusLogic Host Adapter and based on - whether the Tagged Queue Depth value allows queuing - multiple commands. - - TQ:Enable Tagged Queuing will be enabled for all Target Devices - on this Host Adapter overriding any limitation that - would otherwise be imposed based on the Host Adapter - firmware version. - - TQ:Disable Tagged Queuing will be disabled for all Target Devices - on this Host Adapter. - - TQ: Tagged Queuing will be controlled individually for each - Target Device. is a sequence of "Y", - "N", and "X" characters. "Y" enabled Tagged Queuing, - "N" disables Tagged Queuing, and "X" accepts the - default based on the firmware version. The first - character refers to Target Device 0, the second to - Target Device 1, and so on; if the sequence of "Y", - "N", and "X" characters does not cover all the Target - Devices, unspecified characters are assumed to be "X". - - Note that explicitly requesting Tagged Queuing may lead to problems; this - facility is provided primarily to allow disabling Tagged Queuing on Target - Devices that do not implement it correctly. - - The Error Recovery Strategy specification begins with "ER:" and allows for - explicitly specifying the Error Recovery action to be performed when - ResetCommand is called due to a SCSI Command failing to complete - successfully. The following specification options are available: - - ER:Default Error Recovery will select between the Hard Reset and - Bus Device Reset options based on the recommendation - of the SCSI Subsystem. - - ER:HardReset Error Recovery will initiate a Host Adapter Hard Reset - which also causes a SCSI Bus Reset. - - ER:BusDeviceReset Error Recovery will send a Bus Device Reset message to - the individual Target Device causing the error. If - Error Recovery is again initiated for this Target - Device and no SCSI Command to this Target Device has - completed successfully since the Bus Device Reset - message was sent, then a Hard Reset will be attempted. - - ER:None Error Recovery will be suppressed. This option should - only be selected if a SCSI Bus Reset or Bus Device - Reset will cause the Target Device to fail completely - and unrecoverably. - - ER: Error Recovery will be controlled individually for each - Target Device. is a sequence of "D", - "H", "B", and "N" characters. "D" selects Default, "H" - selects Hard Reset, "B" selects Bus Device Reset, and - "N" selects None. The first character refers to Target - Device 0, the second to Target Device 1, and so on; if - the sequence of "D", "H", "B", and "N" characters does - not cover all the possible Target Devices, unspecified - characters are assumed to be "D". - - The Host Adapter Probing specification comprises the following strings: - - NoProbe No probing of any kind is to be performed, and hence - no BusLogic Host Adapters will be detected. - - NoProbeISA No probing of the standard ISA I/O Addresses will - be done, and hence only PCI MultiMaster and FlashPoint - Host Adapters will be detected. - - NoProbePCI No interrogation of PCI Configuration Space will be - made, and hence only ISA Multimaster Host Adapters - will be detected, as well as PCI Multimaster Host - Adapters that have their ISA Compatible I/O Port - set to "Primary" or "Alternate". - - NoSortPCI PCI MultiMaster Host Adapters will be enumerated in - the order provided by the PCI BIOS, ignoring any - setting of the AutoSCSI "Use Bus And Device # For PCI - Scanning Seq." option. - - MultiMasterFirst By default, if both FlashPoint and PCI MultiMaster - Host Adapters are present, this driver will probe for - FlashPoint Host Adapters first unless the BIOS primary - disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will - be probed first. This option forces MultiMaster Host - Adapters to be probed first. - - FlashPointFirst By default, if both FlashPoint and PCI MultiMaster - Host Adapters are present, this driver will probe for - FlashPoint Host Adapters first unless the BIOS primary - disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will - be probed first. This option forces FlashPoint Host - Adapters to be probed first. - - Debug Sets all the tracing bits in BusLogic_GlobalOptions. - -*/ - -void BusLogic_Setup(char *Strings, int *Integers) -{ - BusLogic_CommandLineEntry_T *CommandLineEntry = - &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++]; - int IntegerCount = Integers[0]; - int TargetID, i; - CommandLineEntry->IO_Address = 0; - CommandLineEntry->TaggedQueueDepth = 0; - CommandLineEntry->BusSettleTime = 0; - CommandLineEntry->TaggedQueuingPermitted = 0; - CommandLineEntry->TaggedQueuingPermittedMask = 0; - CommandLineEntry->LocalOptions.All = 0; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_Default, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - if (IntegerCount > 5) - BusLogic_Error("BusLogic: Unexpected Command Line Integers " - "ignored\n", NULL); - if (IntegerCount >= 1) - { - BusLogic_IO_Address_T IO_Address = Integers[1]; - if (IO_Address > 0) - { - BusLogic_ProbeInfo_T *ProbeInfo; - for (i = 0; ; i++) - if (BusLogic_ISA_StandardAddresses[i] == 0) - { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(illegal I/O Address 0x%X)\n", - NULL, IO_Address); - return; - } - else if (i < BusLogic_ProbeInfoCount && - IO_Address == BusLogic_ProbeInfoList[i].IO_Address) - { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(duplicate I/O Address 0x%X)\n", - NULL, IO_Address); - return; - } - else if (IO_Address >= 0x400 || - IO_Address == BusLogic_ISA_StandardAddresses[i]) break; - ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } - CommandLineEntry->IO_Address = IO_Address; - } - if (IntegerCount >= 2) - { - unsigned short TaggedQueueDepth = Integers[2]; - if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth) - { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(illegal Tagged Queue Depth %d)\n", - NULL, TaggedQueueDepth); + The BusLogic Driver Probing Options comprise the following: + + IO: + + The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI + MultiMaster Host Adapter. If neither "IO:" nor "NoProbeISA" options are + specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses + will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134). Multiple + "IO:" options may be specified to precisely determine the I/O Addresses to + be probed, but the probe order will always follow the standard list. + + NoProbe + + The "NoProbe" option disables all probing and therefore no BusLogic Host + Adapters will be detected. + + NoProbeISA + + The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O + Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters + will be detected. + + NoProbePCI + + The "NoProbePCI" options disables the interrogation of PCI Configuration + Space and therefore only ISA Multimaster Host Adapters will be detected, as + well as PCI Multimaster Host Adapters that have their ISA Compatible I/O + Port set to "Primary" or "Alternate". + + NoSortPCI + + The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be + enumerated in the order provided by the PCI BIOS, ignoring any setting of + the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option. + + MultiMasterFirst + + The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed + before FlashPoint Host Adapters. By default, if both FlashPoint and PCI + MultiMaster Host Adapters are present, this driver will probe for + FlashPoint Host Adapters first unless the BIOS primary disk is controlled + by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host + Adapters will be probed first. + + FlashPointFirst + + The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed + before MultiMaster Host Adapters. + + The BusLogic Driver Tagged Queuing Options allow for explicitly specifying + the Queue Depth and whether Tagged Queuing is permitted for each Target + Device (assuming that the Target Device supports Tagged Queuing). The Queue + Depth is the number of SCSI Commands that are allowed to be concurrently + presented for execution (either to the Host Adapter or Target Device). Note + that explicitly enabling Tagged Queuing may lead to problems; the option to + enable or disable Tagged Queuing is provided primarily to allow disabling + Tagged Queuing on Target Devices that do not implement it correctly. The + following options are available: + + QueueDepth: + + The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all + Target Devices that support Tagged Queuing. If no Queue Depth option is + provided, the Queue Depth will be determined automatically based on the + Host Adapter's Total Queue Depth and the number, type, speed, and + capabilities of the detected Target Devices. For Host Adapters that + require ISA Bounce Buffers, the Queue Depth is automatically set by default + to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA + Bounce Buffer memory. Target Devices that do not support Tagged Queuing + always use a Queue Depth of BusLogic_UntaggedQueueDepth. + + QueueDepth:[,...] + + The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth + individually for each Target Device. If an is omitted, the + associated Target Device will have its Queue Depth selected automatically. + + TaggedQueuing:Default + + The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing + based on the firmware version of the BusLogic Host Adapter and based on + whether the Queue Depth allows queuing multiple commands. + + TaggedQueuing:Enable + + The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for + all Target Devices on this Host Adapter, overriding any limitation that + would otherwise be imposed based on the Host Adapter firmware version. + + TaggedQueuing:Disable + + The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing + for all Target Devices on this Host Adapter. + + TaggedQueuing: + + The "TaggedQueuing:" or "TQ:" option controls + Tagged Queuing individually for each Target Device. is a + sequence of "Y", "N", and "X" characters. "Y" enables Tagged Queuing, "N" + disables Tagged Queuing, and "X" accepts the default based on the firmware + version. The first character refers to Target Device 0, the second to + Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters + does not cover all the Target Devices, unspecified characters are assumed + to be "X". + + The BusLogic Driver Error Recovery Option allows for explicitly specifying + the Error Recovery action to be performed when BusLogic_ResetCommand is + called due to a SCSI Command failing to complete successfully. The following + options are available: + + ErrorRecovery:Default + + The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard + Reset and Bus Device Reset options based on the recommendation of the SCSI + Subsystem. + + ErrorRecovery:HardReset + + The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host + Adapter Hard Reset which also causes a SCSI Bus Reset. + + ErrorRecovery:BusDeviceReset + + The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send + a Bus Device Reset message to the individual Target Device causing the + error. If Error Recovery is again initiated for this Target Device and no + SCSI Command to this Target Device has completed successfully since the Bus + Device Reset message was sent, then a Hard Reset will be attempted. + + ErrorRecovery:None + + The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery. + This option should only be selected if a SCSI Bus Reset or Bus Device Reset + will cause the Target Device or a critical operation to suffer a complete + and unrecoverable failure. + + ErrorRecovery: + + The "ErrorRecovery:" or "ER:" option controls + Error Recovery individually for each Target Device. is a + sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H" + selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None. + The first character refers to Target Device 0, the second to Target Device + 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not + cover all the possible Target Devices, unspecified characters are assumed + to be "D". + + The BusLogic Driver Miscellaneous Options comprise the following: + + BusSettleTime: + + The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in + seconds. The Bus Settle Time is the amount of time to wait between a Host + Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI + Commands. If unspecified, it defaults to BusLogic_DefaultBusSettleTime. + + InhibitTargetInquiry + + The "InhibitTargetInquiry" option inhibits the execution of an Inquire + Target Devices or Inquire Installed Devices command on MultiMaster Host + Adapters. This may be necessary with some older Target Devices that do not + respond correctly when Logical Units above 0 are addressed. + + The BusLogic Driver Debugging Options comprise the following: + + TraceProbe + + The "TraceProbe" option enables tracing of Host Adapter Probing. + + TraceHardwareReset + + The "TraceHardwareReset" option enables tracing of Host Adapter Hardware + Reset. + + TraceConfiguration + + The "TraceConfiguration" option enables tracing of Host Adapter + Configuration. + + TraceErrors + + The "TraceErrors" option enables tracing of SCSI Commands that return an + error from the Target Device. The CDB and Sense Data will be printed for + each SCSI Command that fails. + + Debug + + The "Debug" option enables all debugging options. + + The following examples demonstrate setting the Queue Depth for Target Devices + 1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target + Devices on the second host adapter to 31, and the Bus Settle Time on the + second host adapter to 30 seconds. + + Linux Kernel Command Line: + + linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30 + + LILO Linux Boot Loader (in /etc/lilo.conf): + + append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30" + + INSMOD Loadable Kernel Module Installation Facility: + + insmod BusLogic.o \ + 'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"' + + NOTE: Module Utilities 2.1.71 or later is required for correct parsing + of driver options containing commas. + +*/ + +static void BusLogic_ParseDriverOptions(char *OptionsString) +{ + while (true) + { + BusLogic_DriverOptions_T *DriverOptions = + &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; + int TargetID; + memset(DriverOptions, 0, sizeof(BusLogic_DriverOptions_T)); + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + while (*OptionsString != '\0' && *OptionsString != ';') + { + /* Probing Options. */ + if (BusLogic_ParseKeyword(&OptionsString, "IO:")) + { + BusLogic_IO_Address_T IO_Address = + simple_strtoul(OptionsString, &OptionsString, 0); + BusLogic_ProbeOptions.LimitedProbeISA = true; + switch (IO_Address) + { + case 0x330: + BusLogic_ProbeOptions.Probe330 = true; + break; + case 0x334: + BusLogic_ProbeOptions.Probe334 = true; + break; + case 0x230: + BusLogic_ProbeOptions.Probe230 = true; + break; + case 0x234: + BusLogic_ProbeOptions.Probe234 = true; + break; + case 0x130: + BusLogic_ProbeOptions.Probe130 = true; + break; + case 0x134: + BusLogic_ProbeOptions.Probe134 = true; + break; + default: + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal I/O Address 0x%X)\n", + NULL, IO_Address); + return; + } + } + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) + BusLogic_ProbeOptions.NoProbeISA = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) + BusLogic_ProbeOptions.NoProbePCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) + BusLogic_ProbeOptions.NoProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) + BusLogic_ProbeOptions.NoSortPCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) + BusLogic_ProbeOptions.MultiMasterFirst = true; + else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) + BusLogic_ProbeOptions.FlashPointFirst = true; + /* Tagged Queuing Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || + BusLogic_ParseKeyword(&OptionsString, "QD:[")) + { + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + { + unsigned short QueueDepth = + simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth > BusLogic_MaxTaggedQueueDepth) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal Queue Depth %d)\n", + NULL, QueueDepth); + return; + } + DriverOptions->QueueDepth[TargetID] = QueueDepth; + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString == ']') + break; + else + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(',' or ']' expected at '%s')\n", + NULL, OptionsString); + return; + } + } + if (*OptionsString != ']') + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(']' expected at '%s')\n", + NULL, OptionsString); + return; + } + else OptionsString++; + } + else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || + BusLogic_ParseKeyword(&OptionsString, "QD:")) + { + unsigned short QueueDepth = + simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal Queue Depth %d)\n", + NULL, QueueDepth); + return; + } + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->QueueDepth[TargetID] = QueueDepth; + } + else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || + BusLogic_ParseKeyword(&OptionsString, "TQ:")) + { + if (BusLogic_ParseKeyword(&OptionsString, "Default")) + { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0x0000; + } + else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) + { + DriverOptions->TaggedQueuingPermitted = 0xFFFF; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } + else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) + { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } + else + { + unsigned short TargetBit; + for (TargetID = 0, TargetBit = 1; + TargetID < BusLogic_MaxTargetDevices; + TargetID++, TargetBit <<= 1) + switch (*OptionsString++) + { + case 'Y': + DriverOptions->TaggedQueuingPermitted |= TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'N': + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'X': + break; + default: + OptionsString--; + TargetID = BusLogic_MaxTargetDevices; + break; + } + } + } + /* Error Recovery Option. */ + else if (BusLogic_ParseKeyword(&OptionsString, "ErrorRecovery:") || + BusLogic_ParseKeyword(&OptionsString, "ER:")) + { + if (BusLogic_ParseKeyword(&OptionsString, "Default")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + else if (BusLogic_ParseKeyword(&OptionsString, "HardReset")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_HardReset; + else if (BusLogic_ParseKeyword(&OptionsString, "BusDeviceReset")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_BusDeviceReset; + else if (BusLogic_ParseKeyword(&OptionsString, "None")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_None; + else + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + switch (*OptionsString++) + { + case 'D': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + break; + case 'H': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_HardReset; + break; + case 'B': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_BusDeviceReset; + break; + case 'N': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_None; + break; + default: + OptionsString--; + TargetID = BusLogic_MaxTargetDevices; + break; + } + } + /* Miscellaneous Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || + BusLogic_ParseKeyword(&OptionsString, "BST:")) + { + unsigned short BusSettleTime = + simple_strtoul(OptionsString, &OptionsString, 0); + if (BusSettleTime > 5 * 60) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal Bus Settle Time %d)\n", + NULL, BusSettleTime); + return; + } + DriverOptions->BusSettleTime = BusSettleTime; + } + else if (BusLogic_ParseKeyword(&OptionsString, + "InhibitTargetInquiry")) + DriverOptions->LocalOptions.InhibitTargetInquiry = true; + /* Debugging Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) + BusLogic_GlobalOptions.TraceProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) + BusLogic_GlobalOptions.TraceHardwareReset = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) + BusLogic_GlobalOptions.TraceConfiguration = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) + BusLogic_GlobalOptions.TraceErrors = true; + else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) + { + BusLogic_GlobalOptions.TraceProbe = true; + BusLogic_GlobalOptions.TraceHardwareReset = true; + BusLogic_GlobalOptions.TraceConfiguration = true; + BusLogic_GlobalOptions.TraceErrors = true; + } + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString != ';' && *OptionsString != '\0') + { + BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " + "ignored\n", NULL, OptionsString); + *OptionsString = '\0'; + } + } + if (!(BusLogic_DriverOptionsCount == 0 || + BusLogic_ProbeInfoCount == 0 || + BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(all or no I/O Addresses must be specified)\n", NULL); return; } - CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth; + /* + Tagged Queuing is disabled when the Queue Depth is 1 since queuing + multiple commands is not possible. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + if (DriverOptions->QueueDepth[TargetID] == 1) + { + unsigned short TargetBit = 1 << TargetID; + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + } + if (*OptionsString == ';') OptionsString++; + if (*OptionsString == '\0') return; } - if (IntegerCount >= 3) - CommandLineEntry->BusSettleTime = Integers[3]; - if (IntegerCount >= 4) - CommandLineEntry->LocalOptions.All = Integers[4]; - if (IntegerCount >= 5) - BusLogic_GlobalOptions.All |= Integers[5]; - if (!(BusLogic_CommandLineEntryCount == 0 || - BusLogic_ProbeInfoCount == 0 || - BusLogic_CommandLineEntryCount == BusLogic_ProbeInfoCount)) +} + + +/* + BusLogic_Setup handles processing of Kernel Command Line Arguments. +*/ + +void BusLogic_Setup(char *CommandLineString, int *CommandLineIntegers) +{ + if (CommandLineIntegers[0] != 0) { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(all or no I/O Addresses must be specified)\n", NULL); + BusLogic_Error("BusLogic: Obsolete Command Line Entry " + "Format Ignored\n", NULL); return; } - if (Strings == NULL) return; - while (*Strings != '\0') - if (strncmp(Strings, "TQ:", 3) == 0) - { - Strings += 3; - if (strncmp(Strings, "Default", 7) == 0) - Strings += 7; - else if (strncmp(Strings, "Enable", 6) == 0) - { - Strings += 6; - CommandLineEntry->TaggedQueuingPermitted = 0xFFFF; - CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF; - } - else if (strncmp(Strings, "Disable", 7) == 0) - { - Strings += 7; - CommandLineEntry->TaggedQueuingPermitted = 0x0000; - CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF; - } - else - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - switch (*Strings++) - { - case 'Y': - CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID; - CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID; - break; - case 'N': - CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID; - break; - case 'X': - break; - default: - Strings--; - TargetID = BusLogic_MaxTargetDevices; - break; - } - } - else if (strncmp(Strings, "ER:", 3) == 0) - { - Strings += 3; - if (strncmp(Strings, "Default", 7) == 0) - Strings += 7; - else if (strncmp(Strings, "HardReset", 9) == 0) - { - Strings += 9; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_HardReset, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - } - else if (strncmp(Strings, "BusDeviceReset", 14) == 0) - { - Strings += 14; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_BusDeviceReset, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - } - else if (strncmp(Strings, "None", 4) == 0) - { - Strings += 4; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_None, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - } - else - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - switch (*Strings++) - { - case 'D': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_Default; - break; - case 'H': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_HardReset; - break; - case 'B': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_BusDeviceReset; - break; - case 'N': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_None; - break; - default: - Strings--; - TargetID = BusLogic_MaxTargetDevices; - break; - } - } - else if (strcmp(Strings, "NoProbe") == 0 || - strcmp(Strings, "noprobe") == 0) - { - Strings += 7; - BusLogic_ProbeOptions.Bits.NoProbe = true; - } - else if (strncmp(Strings, "NoProbeISA", 10) == 0) - { - Strings += 10; - BusLogic_ProbeOptions.Bits.NoProbeISA = true; - } - else if (strncmp(Strings, "NoProbePCI", 10) == 0) - { - Strings += 10; - BusLogic_ProbeOptions.Bits.NoProbePCI = true; - } - else if (strncmp(Strings, "NoSortPCI", 9) == 0) - { - Strings += 9; - BusLogic_ProbeOptions.Bits.NoSortPCI = true; - } - else if (strncmp(Strings, "MultiMasterFirst", 16) == 0) - { - Strings += 16; - BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst = true; - } - else if (strncmp(Strings, "FlashPointFirst", 15) == 0) - { - Strings += 15; - BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst = true; - } - else if (strncmp(Strings, "Debug", 5) == 0) - { - Strings += 5; - BusLogic_GlobalOptions.Bits.TraceProbe = true; - BusLogic_GlobalOptions.Bits.TraceHardReset = true; - BusLogic_GlobalOptions.Bits.TraceConfiguration = true; - BusLogic_GlobalOptions.Bits.TraceErrors = true; - } - else if (*Strings == ',') - Strings++; - else - { - BusLogic_Error("BusLogic: Unexpected Command Line String '%s' " - "ignored\n", NULL, Strings); - break; - } + if (CommandLineString == NULL || *CommandLineString == '\0') return; + BusLogic_ParseDriverOptions(CommandLineString); } @@ -4724,6 +5020,8 @@ */ #ifdef MODULE + +MODULE_PARM(BusLogic_Options, "s"); SCSI_Host_Template_T driver_template = BUSLOGIC; diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h --- v2.1.86/linux/drivers/scsi/BusLogic.h Fri Feb 6 15:33:40 1998 +++ linux/drivers/scsi/BusLogic.h Thu Feb 12 16:22:17 1998 @@ -6,8 +6,7 @@ This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation, provided that none of the source code or runtime - copyright notices are removed or modified. + Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY @@ -27,6 +26,9 @@ */ +#include + + /* Define types for some of the structures that interface with the rest of the Linux Kernel and SCSI Subsystem. @@ -35,6 +37,7 @@ typedef kdev_t KernelDevice_T; typedef struct proc_dir_entry PROC_DirectoryEntry_T; typedef struct pt_regs Registers_T; +typedef struct partition PartitionTable_T; typedef Scsi_Host_Template SCSI_Host_Template_T; typedef struct Scsi_Host SCSI_Host_T; typedef struct scsi_device SCSI_Device_T; @@ -63,19 +66,19 @@ Define the BusLogic SCSI Host Template structure. */ -#define BUSLOGIC \ - { proc_dir: &BusLogic_ProcDirectoryEntry, /* /proc Directory Entry */ \ - proc_info: BusLogic_ProcDirectoryInfo, /* /proc Info Function */ \ - name: "BusLogic", /* Driver Name */ \ - detect: BusLogic_DetectHostAdapter, /* Detect Host Adapter */ \ - release: BusLogic_ReleaseHostAdapter, /* Release Host Adapter */ \ - info: BusLogic_DriverInfo, /* Driver Info Function */ \ - queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \ - abort: BusLogic_AbortCommand, /* Abort Command Function */ \ - reset: BusLogic_ResetCommand, /* Reset Command Function */ \ - bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ - unchecked_isa_dma: 1, /* Default Unchecked ISA DMA */ \ - use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */ +#define BUSLOGIC \ + { proc_dir: &BusLogic_ProcDirectoryEntry, /* ProcFS Directory Entry */ \ + proc_info: BusLogic_ProcDirectoryInfo, /* ProcFS Info Function */ \ + name: "BusLogic", /* Driver Name */ \ + detect: BusLogic_DetectHostAdapter, /* Detect Host Adapter */ \ + release: BusLogic_ReleaseHostAdapter, /* Release Host Adapter */ \ + info: BusLogic_DriverInfo, /* Driver Info Function */ \ + queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \ + abort: BusLogic_AbortCommand, /* Abort Command Function */ \ + reset: BusLogic_ResetCommand, /* Reset Command Function */ \ + bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ + unchecked_isa_dma: 1, /* Default Initial Value */ \ + use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */ /* @@ -86,6 +89,24 @@ /* + FlashPoint support is only available for the Intel x86 Architecture with + CONFIG_PCI set. +*/ + +#ifndef __i386__ +#undef CONFIG_SCSI_OMIT_FLASHPOINT +#define CONFIG_SCSI_OMIT_FLASHPOINT +#endif + +#ifndef CONFIG_PCI +#undef CONFIG_SCSI_OMIT_FLASHPOINT +#define CONFIG_SCSI_OMIT_FLASHPOINT +#define BusLogic_InitializeProbeInfoListISA \ + BusLogic_InitializeProbeInfoList +#endif + + +/* Define the maximum number of BusLogic Host Adapters supported by this driver. */ @@ -109,16 +130,17 @@ /* - Define the maximum, preferred, and default Queue Depth to allow for Target - Devices depending on whether or not they support Tagged Queuing and whether - or not ISA Bounce Buffers are required. + Define the maximum, maximum automatic, minimum automatic, and default Queue + Depth to allow for Target Devices depending on whether or not they support + Tagged Queuing and whether or not ISA Bounce Buffers are required. */ -#define BusLogic_MaxTaggedQueueDepth 63 -#define BusLogic_PreferredTaggedQueueDepth 28 -#define BusLogic_TaggedQueueDepthBounceBuffers 2 -#define BusLogic_TaggedQueueDepthAutomatic 0 +#define BusLogic_MaxTaggedQueueDepth 64 +#define BusLogic_MaxAutomaticTaggedQueueDepth 28 +#define BusLogic_MinAutomaticTaggedQueueDepth 7 +#define BusLogic_TaggedQueueDepthBB 3 #define BusLogic_UntaggedQueueDepth 3 +#define BusLogic_UntaggedQueueDepthBB 2 /* @@ -132,11 +154,29 @@ /* + Define the maximum number of Mailboxes that should be used for MultiMaster + Host Adapters. This number is chosen to be larger than the maximum Host + Adapter Queue Depth and small enough so that the Host Adapter structure + does not cross an allocation block size boundary. +*/ + +#define BusLogic_MaxMailboxes 211 + + +/* + Define the number of CCBs that should be allocated as a group to optimize + Kernel memory allocation. +*/ + +#define BusLogic_CCB_AllocationGroupSize 7 + + +/* Define the Host Adapter Line and Message Buffer Sizes. */ #define BusLogic_LineBufferSize 100 -#define BusLogic_MessageBufferSize 9900 +#define BusLogic_MessageBufferSize 9700 /* @@ -155,7 +195,27 @@ static char *BusLogic_MessageLevelMap[] = - { KERN_INFO, KERN_INFO, KERN_NOTICE, KERN_WARNING, KERN_ERR }; + { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; + + +/* + Define Driver Message macros. +*/ + +#define BusLogic_Announce(Format, Arguments...) \ + BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments) + +#define BusLogic_Info(Format, Arguments...) \ + BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments) + +#define BusLogic_Notice(Format, Arguments...) \ + BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments) + +#define BusLogic_Warning(Format, Arguments...) \ + BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments) + +#define BusLogic_Error(Format, Arguments...) \ + BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments) /* @@ -175,11 +235,34 @@ #define BusLogic_FlashPointAddressCount 256 static int - BusLogic_HostAdapter_AddressCount[3] = + BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; /* + Define macros for testing the Host Adapter Type. +*/ + +#ifndef CONFIG_SCSI_OMIT_FLASHPOINT + +#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ + (HostAdapter->HostAdapterType == BusLogic_MultiMaster) + +#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ + (HostAdapter->HostAdapterType == BusLogic_FlashPoint) + +#else + +#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ + (true) + +#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ + (false) + +#endif + + +/* Define the possible Host Adapter Bus Types. */ @@ -192,6 +275,7 @@ BusLogic_VESA_Bus = 4, BusLogic_MCA_Bus = 5 } +__attribute__ ((packed)) BusLogic_HostAdapterBusType_T; static char @@ -245,6 +329,13 @@ /* + Define a 32 bit Base Address data type. +*/ + +typedef unsigned int BusLogic_Base_Address_T; + + +/* Define a 32 bit Bus Address data type. */ @@ -276,11 +367,10 @@ typedef struct BusLogic_ProbeInfo { + BusLogic_HostAdapterType_T HostAdapterType; + BusLogic_HostAdapterBusType_T HostAdapterBusType; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; - BusLogic_HostAdapterType_T HostAdapterType:2; - BusLogic_HostAdapterBusType_T HostAdapterBusType:3; - unsigned char :3; unsigned char Bus; unsigned char Device; unsigned char IRQ_Channel; @@ -289,35 +379,24 @@ /* - BusLogic_ISA_StandardAddresses is the list of standard ISA I/O Addresses at - which BusLogic MultiMaster Host Adapters may potentially be found. The first - I/O Address 0x330 is known as the "Primary" I/O Address. A Host Adapter - configured to use the Primary I/O Address will always be the preferred boot - device. -*/ - -#define BusLogic_ISA_StandardAddressesCount 6 - -static BusLogic_IO_Address_T - BusLogic_ISA_StandardAddresses[BusLogic_ISA_StandardAddressesCount] = - { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134 }; - - -/* Define the Probe Options. */ -typedef union BusLogic_ProbeOptions +typedef struct BusLogic_ProbeOptions { - unsigned short All; - struct { - boolean NoProbe:1; /* Bit 0 */ - boolean NoProbeISA:1; /* Bit 1 */ - boolean NoProbePCI:1; /* Bit 2 */ - boolean NoSortPCI:1; /* Bit 3 */ - boolean ProbeMultiMasterFirst:1; /* Bit 4 */ - boolean ProbeFlashPointFirst:1; /* Bit 5 */ - } Bits; + boolean NoProbe:1; /* Bit 0 */ + boolean NoProbeISA:1; /* Bit 1 */ + boolean NoProbePCI:1; /* Bit 2 */ + boolean NoSortPCI:1; /* Bit 3 */ + boolean MultiMasterFirst:1; /* Bit 4 */ + boolean FlashPointFirst:1; /* Bit 5 */ + boolean LimitedProbeISA:1; /* Bit 6 */ + boolean Probe330:1; /* Bit 7 */ + boolean Probe334:1; /* Bit 8 */ + boolean Probe230:1; /* Bit 9 */ + boolean Probe234:1; /* Bit 10 */ + boolean Probe130:1; /* Bit 11 */ + boolean Probe134:1; /* Bit 12 */ } BusLogic_ProbeOptions_T; @@ -326,15 +405,12 @@ Define the Global Options. */ -typedef union BusLogic_GlobalOptions +typedef struct BusLogic_GlobalOptions { - unsigned short All; - struct { - boolean TraceProbe:1; /* Bit 0 */ - boolean TraceHardReset:1; /* Bit 1 */ - boolean TraceConfiguration:1; /* Bit 2 */ - boolean TraceErrors:1; /* Bit 3 */ - } Bits; + boolean TraceProbe:1; /* Bit 0 */ + boolean TraceHardwareReset:1; /* Bit 1 */ + boolean TraceConfiguration:1; /* Bit 2 */ + boolean TraceErrors:1; /* Bit 3 */ } BusLogic_GlobalOptions_T; @@ -343,13 +419,9 @@ Define the Local Options. */ -typedef union BusLogic_LocalOptions +typedef struct BusLogic_LocalOptions { - unsigned short All; - struct { - boolean InhibitTargetInquiry:1; /* Bit 0 */ - boolean InhibitInterruptTest:1; /* Bit 1 */ - } Bits; + boolean InhibitTargetInquiry:1; /* Bit 0 */ } BusLogic_LocalOptions_T; @@ -607,10 +679,13 @@ unsigned char Signature; /* Byte 17 */ unsigned char CharacterD; /* Byte 18 */ unsigned char HostBusType; /* Byte 19 */ - unsigned char :8; /* Byte 20 */ - unsigned char :8; /* Byte 21 */ + unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ + unsigned char WideTransfersActiveID0to7; /* Byte 21 */ BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */ unsigned char DisconnectPermittedID8to15; /* Byte 30 */ + unsigned char :8; /* Byte 31 */ + unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ + unsigned char WideTransfersActiveID8to15; /* Byte 33 */ } BusLogic_SetupInformation_T; @@ -1052,6 +1127,21 @@ /* + Define the Driver CCB Status Codes. +*/ + +typedef enum +{ + BusLogic_CCB_Free = 0, + BusLogic_CCB_Active = 1, + BusLogic_CCB_Completed = 2, + BusLogic_CCB_Reset = 3 +} +__attribute__ ((packed)) +BusLogic_CCB_Status_T; + + +/* Define the 32 Bit Mode Command Control Block (CCB) structure. The first 40 bytes are defined by and common to both the MultiMaster Firmware and the FlashPoint SCCB Manager. The next 60 bytes are defined by the FlashPoint @@ -1101,27 +1191,26 @@ FlashPoint SCCB Manager Defined Portion. */ void (*CallbackFunction)(struct BusLogic_CCB *); /* Bytes 40-43 */ - BusLogic_IO_Address_T BaseAddress; /* Bytes 44-47 */ + BusLogic_Base_Address_T BaseAddress; /* Bytes 44-47 */ BusLogic_CompletionCode_T CompletionCode; /* Byte 48 */ +#ifndef CONFIG_SCSI_OMIT_FLASHPOINT unsigned char :8; /* Byte 49 */ unsigned short OS_Flags; /* Bytes 50-51 */ unsigned char Private[48]; /* Bytes 52-99 */ +#endif /* BusLogic Linux Driver Defined Portion. */ - struct BusLogic_HostAdapter *HostAdapter; - SCSI_Command_T *Command; - enum { BusLogic_CCB_Free = 0, - BusLogic_CCB_Active = 1, - BusLogic_CCB_Completed = 2, - BusLogic_CCB_Reset = 3 } Status; + boolean AllocationGroupHead; + BusLogic_CCB_Status_T Status; unsigned long SerialNumber; + SCSI_Command_T *Command; + struct BusLogic_HostAdapter *HostAdapter; struct BusLogic_CCB *Next; struct BusLogic_CCB *NextAll; BusLogic_ScatterGatherSegment_T ScatterGatherList[BusLogic_ScatterGatherLimit]; } -__attribute__ ((packed)) BusLogic_CCB_T; @@ -1154,32 +1243,48 @@ /* - Define the Linux BusLogic Driver Command Line Entry structure. + Define the BusLogic Driver Options structure. */ -typedef struct BusLogic_CommandLineEntry +typedef struct BusLogic_DriverOptions { - BusLogic_IO_Address_T IO_Address; - unsigned short TaggedQueueDepth; - unsigned short BusSettleTime; unsigned short TaggedQueuingPermitted; unsigned short TaggedQueuingPermittedMask; + unsigned short BusSettleTime; BusLogic_LocalOptions_T LocalOptions; + unsigned char QueueDepth[BusLogic_MaxTargetDevices]; BusLogic_ErrorRecoveryStrategy_T ErrorRecoveryStrategy[BusLogic_MaxTargetDevices]; } -BusLogic_CommandLineEntry_T; +BusLogic_DriverOptions_T; /* - Define the Host Adapter Target Device Statistics structure. + Define the Host Adapter Target Flags structure. +*/ + +typedef struct BusLogic_TargetFlags +{ + boolean TargetExists:1; + boolean TaggedQueuingSupported:1; + boolean WideTransfersSupported:1; + boolean TaggedQueuingActive:1; + boolean WideTransfersActive:1; + boolean CommandSuccessfulFlag:1; + boolean TargetInfoReported:1; +} +BusLogic_TargetFlags_T; + + +/* + Define the Host Adapter Target Statistics structure. */ #define BusLogic_SizeBuckets 10 typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets]; -typedef struct BusLogic_TargetDeviceStatistics +typedef struct BusLogic_TargetStatistics { unsigned int CommandsAttempted; unsigned int CommandsCompleted; @@ -1199,7 +1304,7 @@ unsigned short HostAdapterResetsAttempted; unsigned short HostAdapterResetsCompleted; } -BusLogic_TargetDeviceStatistics_T; +BusLogic_TargetStatistics_T; /* @@ -1218,7 +1323,7 @@ typedef struct FlashPoint_Info { - BusLogic_IO_Address_T BaseAddress; /* Bytes 0-3 */ + BusLogic_Base_Address_T BaseAddress; /* Bytes 0-3 */ boolean Present; /* Byte 4 */ unsigned char IRQ_Channel; /* Byte 5 */ unsigned char SCSI_ID; /* Byte 6 */ @@ -1253,12 +1358,14 @@ /* - Define the Linux BusLogic Driver Host Adapter structure. + Define the BusLogic Driver Host Adapter structure. */ typedef struct BusLogic_HostAdapter { SCSI_Host_T *SCSI_Host; + BusLogic_HostAdapterType_T HostAdapterType; + BusLogic_HostAdapterBusType_T HostAdapterBusType; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; unsigned short AddressCount; @@ -1267,18 +1374,16 @@ unsigned char FirmwareVersion[6]; unsigned char FullModelName[18]; unsigned char InterruptLabel[68]; + unsigned char Bus; + unsigned char Device; unsigned char IRQ_Channel; unsigned char DMA_Channel; unsigned char SCSI_ID; - unsigned char Bus; - unsigned char Device; - BusLogic_HostAdapterType_T HostAdapterType; - BusLogic_HostAdapterBusType_T HostAdapterBusType:3; boolean IRQ_ChannelAcquired:1; boolean DMA_ChannelAcquired:1; boolean ExtendedTranslationEnabled:1; boolean ParityCheckingEnabled:1; - boolean BusResetEnabled; + boolean BusResetEnabled:1; boolean LevelSensitiveInterrupt:1; boolean HostWideSCSI:1; boolean HostDifferentialSCSI:1; @@ -1292,8 +1397,9 @@ boolean StrictRoundRobinModeSupport:1; boolean SCAM_Enabled:1; boolean SCAM_Level2:1; - boolean HostAdapterInitialized; - boolean HostAdapterResetRequested:1; + boolean HostAdapterInitialized:1; + boolean HostAdapterExternalReset:1; + boolean HostAdapterInternalError:1; volatile boolean HostAdapterCommandCompleted:1; unsigned short HostAdapterScatterGatherLimit; unsigned short DriverScatterGatherLimit; @@ -1305,7 +1411,6 @@ unsigned short AllocatedCCBs; unsigned short DriverQueueDepth; unsigned short HostAdapterQueueDepth; - unsigned short TaggedQueueDepth; unsigned short UntaggedQueueDepth; unsigned short BusSettleTime; unsigned short SynchronousPermitted; @@ -1315,26 +1420,24 @@ unsigned short DisconnectPermitted; unsigned short TaggedQueuingPermitted; unsigned short ExternalHostAdapterResets; - BusLogic_LocalOptions_T LocalOptions; + unsigned short HostAdapterInternalErrors; + unsigned short TargetDeviceCount; + unsigned short MessageBufferLength; BusLogic_BusAddress_T BIOS_Address; - BusLogic_InstalledDevices_T InstalledDevices; - BusLogic_SynchronousValues_T SynchronousValues; - BusLogic_SynchronousPeriod_T SynchronousPeriod; - BusLogic_CommandLineEntry_T *CommandLineEntry; - FlashPoint_Info_T *FlashPointInfo; + BusLogic_DriverOptions_T *DriverOptions; + FlashPoint_Info_T FlashPointInfo; FlashPoint_CardHandle_T CardHandle; struct BusLogic_HostAdapter *Next; - char *MessageBuffer; - int MessageBufferLength; + struct BusLogic_HostAdapter *NextAll; BusLogic_CCB_T *All_CCBs; BusLogic_CCB_T *Free_CCBs; BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; BusLogic_ErrorRecoveryStrategy_T ErrorRecoveryStrategy[BusLogic_MaxTargetDevices]; - boolean TaggedQueuingSupported[BusLogic_MaxTargetDevices]; - boolean TaggedQueuingActive[BusLogic_MaxTargetDevices]; - boolean CommandSuccessfulFlag[BusLogic_MaxTargetDevices]; + BusLogic_TargetFlags_T TargetFlags[BusLogic_MaxTargetDevices]; unsigned char QueueDepth[BusLogic_MaxTargetDevices]; + unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; + unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; @@ -1346,7 +1449,11 @@ BusLogic_IncomingMailbox_T *FirstIncomingMailbox; BusLogic_IncomingMailbox_T *LastIncomingMailbox; BusLogic_IncomingMailbox_T *NextIncomingMailbox; - BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics; + BusLogic_TargetStatistics_T TargetStatistics[BusLogic_MaxTargetDevices]; + unsigned char MailboxSpace[BusLogic_MaxMailboxes + * (sizeof(BusLogic_OutgoingMailbox_T) + + sizeof(BusLogic_IncomingMailbox_T))]; + char MessageBuffer[BusLogic_MessageBufferSize]; } BusLogic_HostAdapter_T; @@ -1365,6 +1472,41 @@ /* + Define a structure for the SCSI Inquiry command results. +*/ + +typedef struct SCSI_Inquiry +{ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char :2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char :8; /* Byte 5 */ + unsigned char :8; /* Byte 6 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean :1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ +} +SCSI_Inquiry_T; + + +/* BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter. */ @@ -1540,6 +1682,19 @@ /* + Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and + 32 Bit Kernel Virtual Addresses. This avoids compilation warnings + on 64 Bit architectures. +*/ + +static inline +BusLogic_BusAddress_T Virtual_to_32Bit_Virtual(void *VirtualAddress) +{ + return (BusLogic_BusAddress_T) (unsigned long) VirtualAddress; +} + + +/* BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at 65535 rather than wrapping around to 0. */ @@ -1577,93 +1732,38 @@ { int Index = 0; if (Amount < 8*1024) - if (Amount < 2*1024) - Index = (Amount < 1*1024 ? 0 : 1); - else Index = (Amount < 4*1024 ? 2 : 3); + { + if (Amount < 2*1024) + Index = (Amount < 1*1024 ? 0 : 1); + else Index = (Amount < 4*1024 ? 2 : 3); + } else if (Amount < 128*1024) - if (Amount < 32*1024) - Index = (Amount < 16*1024 ? 4 : 5); - else Index = (Amount < 64*1024 ? 6 : 7); + { + if (Amount < 32*1024) + Index = (Amount < 16*1024 ? 4 : 5); + else Index = (Amount < 64*1024 ? 6 : 7); + } else Index = (Amount < 256*1024 ? 8 : 9); CommandSizeBuckets[Index]++; } /* - If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT, and use the - ISA only probe function as the general one. + Define compatibility macros between Linux 2.0 and Linux 2.1. */ -#ifndef CONFIG_PCI - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT +#if LINUX_VERSION_CODE < 0x20100 -#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList +#define MODULE_PARM(Variable, Type) #endif /* - FlashPoint support is only available for the Intel x86 Architecture. -*/ - -#ifndef __i386__ - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT - -#endif - - -/* - Define macros for testing the Host Adapter Type. -*/ - -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT - -#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ - (HostAdapter->HostAdapterType == BusLogic_MultiMaster) - -#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ - (HostAdapter->HostAdapterType == BusLogic_FlashPoint) - -#else - -#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ - (true) - -#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ - (false) - -#endif - - -/* - Define Driver Message Macros. -*/ - -#define BusLogic_Announce(Format, Arguments...) \ - BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments) - -#define BusLogic_Info(Format, Arguments...) \ - BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments) - -#define BusLogic_Notice(Format, Arguments...) \ - BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments) - -#define BusLogic_Warning(Format, Arguments...) \ - BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments) - -#define BusLogic_Error(Format, Arguments...) \ - BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments) - - -/* Define the version number of the FlashPoint Firmware (SCCB Manager). */ -#define FlashPoint_FirmwareVersion "5.01" +#define FlashPoint_FirmwareVersion "5.02" /* @@ -1671,35 +1771,22 @@ */ #define FlashPoint_NormalInterrupt 0x00 +#define FlashPoint_InternalError 0xFE #define FlashPoint_ExternalBusReset 0xFF /* - Define prototypes for the FlashPoint SCCB Manager Functions. -*/ - -extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *); -extern FlashPoint_CardHandle_T - FlashPoint_HardResetHostAdapter(FlashPoint_Info_T *); -extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); -extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); -extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T); -extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); -extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); - - -/* Define prototypes for the forward referenced BusLogic Driver Internal Functions. */ -static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB); +static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *); static void BusLogic_InterruptHandler(int, void *, Registers_T *); static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *, - SCSI_Command_T *, - unsigned int); -static void BusLogic_Message(BusLogic_MessageLevel_T, char *Format, + SCSI_Command_T *, unsigned int); +static void BusLogic_Message(BusLogic_MessageLevel_T, char *, BusLogic_HostAdapter_T *, ...); +static void BusLogic_ParseDriverOptions(char *); #endif /* BusLogic_DriverVersion */ diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/FlashPoint.c linux/drivers/scsi/FlashPoint.c --- v2.1.86/linux/drivers/scsi/FlashPoint.c Mon Aug 11 00:10:00 1997 +++ linux/drivers/scsi/FlashPoint.c Sat Jan 31 02:00:00 1998 @@ -19,40 +19,15 @@ #include -/* - If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT. -*/ - -#ifndef CONFIG_PCI - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT - -#endif - - -/* - FlashPoint support is only available for the Intel x86 Architecture. -*/ - -#ifndef __i386__ - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT - -#endif - - #ifndef CONFIG_SCSI_OMIT_FLASHPOINT #define UNIX #define FW_TYPE _SCCB_MGR_ #define MAX_CARDS 8 +#undef BUSTYPE_PCI -#include - #define OS_InPortByte(port) inb(port) #define OS_InPortWord(port) inw(port) #define OS_InPortLong(port) inl(port) @@ -68,7 +43,7 @@ */ #define SccbMgr_sense_adapter FlashPoint_ProbeHostAdapter -#define SccbMgr_config_adapter FlashPoint_HardResetHostAdapter +#define SccbMgr_config_adapter FlashPoint_HardwareResetHostAdapter #define SccbMgr_unload_card FlashPoint_ReleaseHostAdapter #define SccbMgr_start_sccb FlashPoint_StartCCB #define SccbMgr_abort_sccb FlashPoint_AbortCCB @@ -169,6 +144,7 @@ #define stwidn FPT_stwidn #define sxfrp FPT_sxfrp #define utilEERead FPT_utilEERead +#define utilEEReadOrg FPT_utilEEReadOrg #define utilEESendCmdAddr FPT_utilEESendCmdAddr #define utilEEWrite FPT_utilEEWrite #define utilEEWriteOnOff FPT_utilEEWriteOnOff @@ -1317,9 +1293,9 @@ * * Description: Register definitions for HARPOON ASIC. * - * $Date: 1997/01/31 02:14:28 $ + * $Date: 1997/07/09 21:44:36 $ * - * $Revision: 1.6 $ + * $Revision: 1.9 $ * *----------------------------------------------------------------------*/ @@ -2070,9 +2046,14 @@ UCHAR RdStack(USHORT port, UCHAR index); void WrStack(USHORT portBase, UCHAR index, UCHAR data); UCHAR ChkIfChipInitialized(USHORT ioPort); + +#if defined(V302) UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun); +#endif + void SendMsg(USHORT port, UCHAR message); void queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code); +UCHAR scsellDOS(USHORT p_port, UCHAR targ_id); #else UCHAR sfm(ULONG port, PSCCB pcurrSCCB); void scsiStartAuto(ULONG port); @@ -2090,7 +2071,11 @@ UCHAR RdStack(ULONG port, UCHAR index); void WrStack(ULONG portBase, UCHAR index, UCHAR data); UCHAR ChkIfChipInitialized(ULONG ioPort); + +#if defined(V302) UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tar, PUCHAR lun); +#endif + void SendMsg(ULONG port, UCHAR message); void queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code); #endif @@ -2130,6 +2115,7 @@ void utilEEWriteOnOff(USHORT p_port,UCHAR p_mode); void utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr); USHORT utilEERead(USHORT p_port, USHORT ee_addr); +USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr); void utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr); #else void Wait1Second(ULONG p_port); @@ -2137,6 +2123,7 @@ void utilEEWriteOnOff(ULONG p_port,UCHAR p_mode); void utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr); USHORT utilEERead(ULONG p_port, USHORT ee_addr); +USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr); void utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr); #endif @@ -2339,7 +2326,7 @@ extern unsigned int SccbGlobalFlags; -#ident "$Id: sccb.c 1.17 1997/02/11 21:06:41 mohan Exp $" +#ident "$Id: sccb.c 1.18 1997/06/10 16:47:04 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -2353,9 +2340,9 @@ * Description: Functions relating to handling of the SCCB interface * between the device driver and the HARPOON. * - * $Date: 1997/02/11 21:06:41 $ + * $Date: 1997/06/10 16:47:04 $ * - * $Revision: 1.17 $ + * $Revision: 1.18 $ * *----------------------------------------------------------------------*/ @@ -2477,6 +2464,7 @@ if(ChkIfChipInitialized(ioport) == FALSE) { pCurrNvRam = NULL; + WR_HARPOON(ioport+hp_semaphore, 0x00); XbowInit(ioport, 0); /*Must Init the SCSI before attempting */ DiagEEPROM(ioport); } @@ -3036,6 +3024,7 @@ if(ChkIfChipInitialized(ioport) == FALSE) { pCurrNvRam = NULL; + WR_HARPOON(ioport+hp_semaphore, 0x00); XbowInit(ioport, 0); /*Must Init the SCSI before attempting */ DiagEEPROM(ioport); } @@ -4802,7 +4791,23 @@ may not show up if another device reselects us in 1.5us or less. SRR Wednesday, 3/8/1995. */ - while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) ; + while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)) && + !((RDW_HARPOON((ioport+hp_intstat)) & PHASE) && + RD_HARPOON((ioport+hp_scsisig)) == + (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | SCSI_IOBIT))) ; + + /* + The additional loop exit condition above detects a timing problem + with the revision D/E harpoon chips. The caller should reset the + host adapter to recover when 0xFE is returned. + */ + if (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) + { + mOS_Lock((PSCCBcard)pCurrCard); + MENABLE_INT(ioport); + mOS_UnLock((PSCCBcard)pCurrCard); + return 0xFE; + } WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC)); @@ -5347,7 +5352,7 @@ } #endif -#ident "$Id: sccb_dat.c 1.9 1997/01/31 02:12:58 mohan Exp $" +#ident "$Id: sccb_dat.c 1.10 1997/02/22 03:16:02 awin Exp $" /*---------------------------------------------------------------------- * * @@ -5361,9 +5366,9 @@ * Description: Functions relating to handling of the SCCB interface * between the device driver and the HARPOON. * - * $Date: 1997/01/31 02:12:58 $ + * $Date: 1997/02/22 03:16:02 $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * *----------------------------------------------------------------------*/ @@ -5378,18 +5383,19 @@ /*#include */ /*#include */ +/* +** IMPORTANT NOTE!!! +** +** You MUST preassign all data to a valid value or zero. This is +** required due to the MS compiler bug under OS/2 and Solaris Real-Mode +** driver environment. +*/ + -#if defined(OS2) || defined (SOLARIS_REAL_MODE) -SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { 0 }; -SCCBCARD BL_Card[MAX_CARDS] = { 0 }; -SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { 0 }; -NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { 0 }; -#else -SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR]; -SCCBCARD BL_Card[MAX_CARDS]; -SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR]; -NVRAMINFO nvRamInfo[MAX_MB_CARDS]; -#endif +SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { { { 0 } } }; +SCCBCARD BL_Card[MAX_CARDS] = { { 0 } }; +SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { { { 0 } } }; +NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { { 0 } }; #if defined(OS2) @@ -5402,23 +5408,23 @@ #endif #if defined(DOS) -UCHAR first_time; +UCHAR first_time = 0; #endif -UCHAR mbCards; +UCHAR mbCards = 0; UCHAR scamHAString[] = {0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', \ ' ', 'B', 'T', '-', '9', '3', '0', \ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; -USHORT default_intena; +USHORT default_intena = 0; #if defined(BUGBUG) -UCHAR debug_int[MAX_CARDS][debug_size]; -UCHAR debug_index[MAX_CARDS]; -UCHAR reserved_1[3]; +UCHAR debug_int[MAX_CARDS][debug_size] = { 0 }; +UCHAR debug_index[MAX_CARDS] = { 0 }; +UCHAR reserved_1[3] = { 0 }; #endif -#ident "$Id: scsi.c 1.19 1997/01/31 02:08:14 mohan Exp $" +#ident "$Id: scsi.c 1.23 1997/07/09 21:42:54 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -5433,9 +5439,9 @@ * selection/reselection, sync negotiation, message-in * decoding. * - * $Date: 1997/01/31 02:08:14 $ + * $Date: 1997/07/09 21:42:54 $ * - * $Revision: 1.19 $ + * $Revision: 1.23 $ * *----------------------------------------------------------------------*/ @@ -5483,11 +5489,13 @@ while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) && (TimeOutLoop++ < 20000) ){} + WR_HARPOON(port+hp_portctrl_0, SCSI_PORT); message = RD_HARPOON(port+hp_scsidata_0); - WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + WR_HARPOON(port+hp_scsisig, SCSI_ACK + S_MSGI_PH); + if (TimeOutLoop > 20000) message = 0x00; /* force message byte = 0 if Time Out on Req */ @@ -5495,6 +5503,10 @@ if ((RDW_HARPOON((port+hp_intstat)) & PARITY) && (RD_HARPOON(port+hp_addstat) & SCSI_PAR_ERR)) { + WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + WR_HARPOON(port+hp_xferstat, 0); + WR_HARPOON(port+hp_fiforead, 0); + WR_HARPOON(port+hp_fifowrite, 0); if (pCurrSCCB != NULL) { pCurrSCCB->Sccb_scsimsg = SMPARITY; @@ -5503,6 +5515,7 @@ do { ACCEPT_MSG_ATN(port); + TimeOutLoop = 0; while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) && (TimeOutLoop++ < 20000) ){} if (TimeOutLoop > 20000) @@ -5524,6 +5537,10 @@ }while(1); } + WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + WR_HARPOON(port+hp_xferstat, 0); + WR_HARPOON(port+hp_fiforead, 0); + WR_HARPOON(port+hp_fifowrite, 0); return(message); } @@ -5894,12 +5911,20 @@ void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard) #endif { + +#if defined(V302) #ifdef DOS UCHAR our_target,message, msgRetryCount; extern UCHAR lun, tag; #else UCHAR our_target,message,lun,tag, msgRetryCount; #endif + +#else /* V302 */ + UCHAR our_target, message, lun = 0, tag, msgRetryCount; +#endif /* V302 */ + + PSCCBMgr_tar_info currTar_Info; PSCCB currSCCB; @@ -5972,7 +5997,103 @@ msgRetryCount = 0; do { + +#if defined(V302) + message = GetTarLun(port, p_card, our_target, pCurrCard, &tag, &lun); + +#else /* V302 */ + + currTar_Info = &sccbMgrTbl[p_card][our_target]; + tag = 0; + + + while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) + { + if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) + { + + WRW_HARPOON((port+hp_intstat), PHASE); + return; + } + } + + WRW_HARPOON((port+hp_intstat), PHASE); + if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH) + { + + message = sfm(port,pCurrCard->currentSCCB); + if (message) + { + + if (message <= (0x80 | LUN_MASK)) + { + lun = message & (UCHAR)LUN_MASK; + +#if !defined(DOS) + if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING) + { + if (currTar_Info->TarTagQ_Cnt != 0) + { + + if (!(currTar_Info->TarLUN_CA)) + { + ACCEPT_MSG(port); /*Release the ACK for ID msg. */ + + + message = sfm(port,pCurrCard->currentSCCB); + if (message) + { + ACCEPT_MSG(port); + } + + else + message = FALSE; + + if(message != FALSE) + { + tag = sfm(port,pCurrCard->currentSCCB); + + if (!(tag)) + message = FALSE; + } + + } /*C.A. exists! */ + + } /*End Q cnt != 0 */ + + } /*End Tag cmds supported! */ +#endif /* !DOS */ + + } /*End valid ID message. */ + + else + { + + ACCEPT_MSG_ATN(port); + } + + } /* End good id message. */ + + else + { + + message = FALSE; + } + } + else + { + ACCEPT_MSG_ATN(port); + + while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) && + !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) && + (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ; + + return; + } + +#endif /* V302 */ + if(message == FALSE) { msgRetryCount++; @@ -6071,6 +6192,8 @@ (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ; } +#if defined(V302) + #if defined(DOS) UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun) #else @@ -6162,6 +6285,7 @@ return(TRUE); } +#endif /* V302 */ #if defined(DOS) void SendMsg(USHORT port, UCHAR message) @@ -6469,6 +6593,10 @@ ACCEPT_MSG(port); WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START)); } + }else + { + if(pCurrSCCB->Sccb_scsimsg == SMPARITY) + WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START)); } } @@ -7386,6 +7514,7 @@ p_sccb->Sccb_scsistat = BUS_FREE_ST; p_sccb->SccbStatus = SCCB_IN_PROCESS; p_sccb->Sccb_scsimsg = SMNO_OP; + } @@ -9222,7 +9351,7 @@ currSCCB->Sccb_XferCnt = currSCCB->DataLength - currSCCB->Sccb_ATC; } } -#ident "$Id: scam.c 1.16 1997/01/31 02:11:12 mohan Exp $" +#ident "$Id: scam.c 1.17 1997/03/20 23:49:37 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -9237,9 +9366,9 @@ * and the determination of the SCSI IDs to be assigned * to all perspective SCSI targets. * - * $Date: 1997/01/31 02:11:12 $ + * $Date: 1997/03/20 23:49:37 $ * - * $Revision: 1.16 $ + * $Revision: 1.17 $ * *----------------------------------------------------------------------*/ @@ -9468,7 +9597,7 @@ if (((ScamFlg & SCAM_ENABLED) && (scamInfo[i].state == LEGACY)) || (i != p_our_id)) { - scsell(p_port,i); + scsellDOS(p_port,i); } } #endif @@ -9885,6 +10014,7 @@ } if ((ret_data & 0x1F) == 0) + { /* if(bit_cnt != 0 || bit_cnt != 8) { @@ -9899,6 +10029,7 @@ return(0x00); else return(0xFF); + } } /*bit loop */ @@ -10090,6 +10221,90 @@ } } +#if defined(DOS) +/*--------------------------------------------------------------------- + * + * Function: scsell for DOS + * + * Description: Select the specified device ID using a selection timeout + * less than 2ms. This was specially required to solve + * the problem with Plextor 12X CD-ROM drive. This drive + * was responding the Selection at the end of 4ms and + * hanging the system. + * + *---------------------------------------------------------------------*/ + +UCHAR scsellDOS(USHORT p_port, UCHAR targ_id) +{ + USHORT i; + + WR_HARPOON(p_port+hp_page_ctrl, + (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE)); + + ARAM_ACCESS(p_port); + + WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER)); + WR_HARPOON(p_port+hp_seltimeout,TO_2ms); + + + for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) { + WRW_HARPOON(i, (MPM_OP+ACOMMAND)); + } + WRW_HARPOON(i, (BRH_OP+ALWAYS+ NP)); + + WRW_HARPOON((p_port+hp_intstat), + (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT)); + + WR_HARPOON(p_port+hp_select_id, targ_id); + + WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT); + WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT)); + WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL)); + + + while (!(RDW_HARPOON((p_port+hp_intstat)) & + (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {} + + if (RDW_HARPOON((p_port+hp_intstat)) & RESET) + Wait(p_port, TO_250ms); + + DISABLE_AUTO(p_port); + + WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER)); + WR_HARPOON(p_port+hp_seltimeout,TO_290ms); + + SGRAM_ACCESS(p_port); + + if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) { + + WRW_HARPOON((p_port+hp_intstat), + (RESET | TIMEOUT | SEL | BUS_FREE | PHASE)); + + WR_HARPOON(p_port+hp_page_ctrl, + (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE)); + + return(FALSE); /*No legacy device */ + } + + else { + + while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) { + if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ) + { + WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + ACCEPT_MSG(p_port); + } + } + + WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1); + + WR_HARPOON(p_port+hp_page_ctrl, + (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE)); + + return(TRUE); /*Found one of them oldies! */ + } +} +#endif /* DOS */ /*--------------------------------------------------------------------- * @@ -10252,10 +10467,12 @@ match--; if (match == 0xFF) + { if (p_id_string[0] & BIT(5)) match = 7; else match = MAX_SCSI_TAR-1; + } } @@ -10300,10 +10517,12 @@ match--; if (match == 0xFF) + { if (p_id_string[0] & BIT(5)) match = 7; else match = MAX_SCSI_TAR-1; + } } return(NO_ID_AVAIL); @@ -10362,7 +10581,7 @@ utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM/2); utilEEWriteOnOff(p_port,0); /* Turn off write access */ } -#ident "$Id: diagnose.c 1.9 1997/01/31 02:09:48 mohan Exp $" +#ident "$Id: diagnose.c 1.10 1997/06/10 16:51:47 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -10376,9 +10595,9 @@ * Description: Diagnostic funtions for testing the integrity of * the HARPOON. * - * $Date: 1997/01/31 02:09:48 $ + * $Date: 1997/06/10 16:51:47 $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * *----------------------------------------------------------------------*/ @@ -10419,7 +10638,7 @@ WR_HARPOON(port+hp_scsireset,(DMA_RESET | HPSCSI_RESET | PROG_RESET | \ FIFO_CLR)); - WR_HARPOON(port+hp_scsireset,0x00); + WR_HARPOON(port+hp_scsireset,SCSI_INI); WR_HARPOON(port+hp_clkctrl_0,CLKCTRL_DEFAULT); @@ -10703,8 +10922,8 @@ temp += 0x70D3; utilEEWrite(p_port, 0x0010, BIOS_CONFIG/2); temp += 0x0010; - utilEEWrite(p_port, 0x0007, SCAM_CONFIG/2); - temp += 0x0007; + utilEEWrite(p_port, 0x0003, SCAM_CONFIG/2); + temp += 0x0003; utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID/2); temp += 0x0007; @@ -10807,7 +11026,7 @@ } -#ident "$Id: utility.c 1.22 1997/01/31 02:12:23 mohan Exp $" +#ident "$Id: utility.c 1.23 1997/06/10 16:55:06 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -10821,9 +11040,9 @@ * Description: Utility functions relating to queueing and EEPROM * manipulation and any other garbage functions. * - * $Date: 1997/01/31 02:12:23 $ + * $Date: 1997/06/10 16:55:06 $ * - * $Revision: 1.22 $ + * $Revision: 1.23 $ * *----------------------------------------------------------------------*/ /*#include */ @@ -11617,10 +11836,13 @@ ee_value &= ~SEE_DO; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); } ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H); WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS)); @@ -11632,7 +11854,6 @@ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); /* Turn off Master Select */ } - /*--------------------------------------------------------------------- * * Function: Read EEPROM @@ -11648,6 +11869,40 @@ USHORT utilEERead(ULONG p_port, USHORT ee_addr) #endif { + USHORT i, ee_data1, ee_data2; + + i = 0; + ee_data1 = utilEEReadOrg(p_port, ee_addr); + do + { + ee_data2 = utilEEReadOrg(p_port, ee_addr); + + if(ee_data1 == ee_data2) + return(ee_data1); + + ee_data1 = ee_data2; + i++; + + }while(i < 4); + + return(ee_data1); +} + +/*--------------------------------------------------------------------- + * + * Function: Read EEPROM Original + * + * Description: Read a word from the EEPROM at the desired + * address. + * + *---------------------------------------------------------------------*/ + +#if defined(DOS) +USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr) +#else +USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr) +#endif +{ UCHAR ee_value; USHORT i, ee_data; @@ -11666,8 +11921,10 @@ ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_data <<= 1; @@ -11722,10 +11979,13 @@ ee_value &= ~SEE_DO; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); } @@ -11744,10 +12004,13 @@ ee_value &= ~SEE_DO; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); i >>= 1; } @@ -11783,6 +12046,114 @@ return(lrc); } + + +/* + The following inline definitions avoid type conflicts. +*/ + +static inline unsigned char +FlashPoint__ProbeHostAdapter(FlashPoint_Info_T *FlashPointInfo) +{ + return FlashPoint_ProbeHostAdapter((PSCCBMGR_INFO) FlashPointInfo); +} + + +static inline FlashPoint_CardHandle_T +FlashPoint__HardwareResetHostAdapter(FlashPoint_Info_T *FlashPointInfo) +{ + return FlashPoint_HardwareResetHostAdapter((PSCCBMGR_INFO) FlashPointInfo); +} + +static inline void +FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle) +{ + FlashPoint_ReleaseHostAdapter(CardHandle); +} + + +static inline void +FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB) +{ + FlashPoint_StartCCB(CardHandle, (PSCCB) CCB); +} + + +static inline void +FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB) +{ + FlashPoint_AbortCCB(CardHandle, (PSCCB) CCB); +} + + +static inline boolean +FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle) +{ + return FlashPoint_InterruptPending(CardHandle); +} + + +static inline int +FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle) +{ + return FlashPoint_HandleInterrupt(CardHandle); +} + + +#define FlashPoint_ProbeHostAdapter FlashPoint__ProbeHostAdapter +#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter +#define FlashPoint_ReleaseHostAdapter FlashPoint__ReleaseHostAdapter +#define FlashPoint_StartCCB FlashPoint__StartCCB +#define FlashPoint_AbortCCB FlashPoint__AbortCCB +#define FlashPoint_InterruptPending FlashPoint__InterruptPending +#define FlashPoint_HandleInterrupt FlashPoint__HandleInterrupt + + +/* + FlashPoint_InquireTargetInfo returns the Synchronous Period, Synchronous + Offset, and Wide Transfers Active information for TargetID on CardHandle. +*/ + +void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T CardHandle, + int TargetID, + unsigned char *SynchronousPeriod, + unsigned char *SynchronousOffset, + unsigned char *WideTransfersActive) +{ + SCCBMGR_TAR_INFO *TargetInfo = + &sccbMgrTbl[((SCCBCARD *)CardHandle)->cardIndex][TargetID]; + if ((TargetInfo->TarSyncCtrl & SYNC_OFFSET) > 0) + { + *SynchronousPeriod = 5 * ((TargetInfo->TarSyncCtrl >> 5) + 1); + *SynchronousOffset = TargetInfo->TarSyncCtrl & SYNC_OFFSET; + } + else + { + *SynchronousPeriod = 0; + *SynchronousOffset = 0; + } + *WideTransfersActive = (TargetInfo->TarSyncCtrl & NARROW_SCSI ? 0 : 1); +} + + +#else /* CONFIG_SCSI_OMIT_FLASHPOINT */ + + +/* + Define prototypes for the FlashPoint SCCB Manager Functions. +*/ + +extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *); +extern FlashPoint_CardHandle_T + FlashPoint_HardwareResetHostAdapter(FlashPoint_Info_T *); +extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); +extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); +extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T); +extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); +extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); +extern void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T, + int, unsigned char *, + unsigned char *, unsigned char *); #endif /* CONFIG_SCSI_OMIT_FLASHPOINT */ diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.86/linux/drivers/scsi/Makefile Fri Jan 23 18:10:32 1998 +++ linux/drivers/scsi/Makefile Thu Feb 12 15:48:43 1998 @@ -464,14 +464,6 @@ include $(TOPDIR)/Rules.make -# This gives correct output but uses old-style "excessive compilation". -# This will be fixed soon (about December 1997 or January 1998). -BusLogic.o: BusLogic.c FlashPoint.c ../../include/linux/autoconf.h - $(CC) $(CFLAGS) -c BusLogic.c -o BusLogic.O - $(CC) $(CFLAGS) -c FlashPoint.c -o FlashPoint.O - $(LD) -r -o BusLogic.o BusLogic.O FlashPoint.O - rm -f BusLogic.O FlashPoint.O - 53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl ln -sf 53c7,8xx.scr fake.c $(CPP) -traditional -DCHIP=810 fake.c | grep -v '^#' | perl script_asm.pl diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/README.BusLogic linux/drivers/scsi/README.BusLogic --- v2.1.86/linux/drivers/scsi/README.BusLogic Mon Aug 11 00:10:00 1997 +++ linux/drivers/scsi/README.BusLogic Sat Jan 31 02:00:00 1998 @@ -1,10 +1,10 @@ BusLogic MultiMaster and FlashPoint SCSI Driver for Linux - Version 2.0.10 for Linux 2.0 + Version 2.0.11 for Linux 2.0 PRODUCTION RELEASE - 11 August 1997 + 31 January 1998 Leonard N. Zubkoff Dandelion Digital @@ -15,27 +15,34 @@ INTRODUCTION -BusLogic, Inc. designs and manufactures a variety of high performance SCSI host -adapters which share a common programming interface across a diverse collection -of bus architectures by virtue of their MultiMaster ASIC technology. This -driver supports all present BusLogic MultiMaster Host Adapters, and should +BusLogic, Inc. designed and manufactured a variety of high performance SCSI +host adapters which share a common programming interface across a diverse +collection of bus architectures by virtue of their MultiMaster ASIC technology. +BusLogic was acquired by Mylex Corporation in February 1996, but the products +supported by this driver originated under the BusLogic name and so that name is +retained in the source code and documentation. + +This driver supports all present BusLogic MultiMaster Host Adapters, and should support any future MultiMaster designs with little or no modification. More -recently, BusLogic has introduced the FlashPoint Host Adapters, which are less +recently, BusLogic introduced the FlashPoint Host Adapters, which are less costly and rely on the host CPU, rather than including an onboard processor. -Mylex/BusLogic has recently provided me with the FlashPoint Driver Developer's -Kit, which comprises documentation and freely redistributable source code for -the FlashPoint SCCB Manager. The SCCB Manager is the library of code that runs -on the host CPU and performs functions analogous to the firmware on the -MultiMaster Host Adapters. Thanks to their having provided the SCCB Manager, -this driver now supports the FlashPoint Host Adapters as well. +Despite not having an onboard CPU, the FlashPoint Host Adapters perform very +well and have very low command latency. BusLogic has recently provided me with +the FlashPoint Driver Developer's Kit, which comprises documentation and freely +redistributable source code for the FlashPoint SCCB Manager. The SCCB Manager +is the library of code that runs on the host CPU and performs functions +analogous to the firmware on the MultiMaster Host Adapters. Thanks to their +having provided the SCCB Manager, this driver now supports the FlashPoint Host +Adapters as well. My primary goals in writing this completely new BusLogic driver for Linux are to achieve the full performance that BusLogic SCSI Host Adapters and modern SCSI peripherals are capable of, and to provide a highly robust driver that can be depended upon for high performance mission critical applications. All of the major performance and error recovery features can be configured from the -Linux kernel command line, allowing individual installations to tune driver -performance and error recovery to their particular needs. +Linux kernel command line or at module initialization time, allowing individual +installations to tune driver performance and error recovery to their particular +needs. The latest information on Linux support for BusLogic SCSI Host Adapters, as well as the most recent release of this driver and the latest firmware for the @@ -48,33 +55,35 @@ relevant to SCSI operations, and a detailed description of your system's hardware configuration. -BusLogic has been an excellent company to work with and I highly recommend -their products to the Linux community. In November 1995, I was offered the +Mylex has been an excellent company to work with and I highly recommend their +products to the Linux community. In November 1995, I was offered the opportunity to become a beta test site for their latest MultiMaster product, the BT-948 PCI Ultra SCSI Host Adapter, and then again for the BT-958 PCI Wide Ultra SCSI Host Adapter in January 1996. This was mutually beneficial since -BusLogic received a degree and kind of testing that their own testing group -cannot readily achieve, and the Linux community has available high performance -host adapters that have been well tested with Linux even before being brought -to market. This relationship has also given me the opportunity to interact +Mylex received a degree and kind of testing that their own testing group cannot +readily achieve, and the Linux community has available high performance host +adapters that have been well tested with Linux even before being brought to +market. This relationship has also given me the opportunity to interact directly with their technical staff, to understand more about the internal workings of their products, and in turn to educate them about the needs and -potential of the Linux community. Their interest and support is greatly -appreciated. +potential of the Linux community. + +More recently, Mylex has reaffirmed the company's interest in supporting the +Linux community, and I am now working on a Linux driver for the DAC960 PCI RAID +Controllers. Mylex's interest and support is greatly appreciated. -Unlike some other vendors, if you contact BusLogic Technical Support with a +Unlike some other vendors, if you contact Mylex Technical Support with a problem and are running Linux, they will not tell you that your use of their products is unsupported. Their latest product marketing literature even states -"BusLogic SCSI host adapters are compatible with all major operating systems +"Mylex SCSI host adapters are compatible with all major operating systems including: ... Linux ...". -BusLogic, Inc. is located at 4151 Burton Drive, Santa Clara, California, 95054, -USA and can be reached by Voice at 408/492-9090 or by FAX at 408/492-1542. -BusLogic maintains a World Wide Web site at http://www.buslogic.com, an -anonymous FTP site at ftp.buslogic.com, and a BBS at 408/492-1984. BusLogic -Technical Support can be reached by electronic mail at techsup@buslogic.com, by -Voice at 408/654-0760, or by FAX at 408/492-1542. Contact information for -offices in Europe and Japan is available on the Web site. +Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, California +94555, USA and can be reached at 510/796-6100 or on the World Wide Web at +http://www.mylex.com. Mylex Technical Support can be reached by electronic +mail at techsup@mylex.com, by Voice at 510/608-2400, or by FAX at 510/745-7715. +Contact information for offices in Europe and Japan is available on the Web +site. DRIVER FEATURES @@ -83,15 +92,46 @@ During system initialization, the driver reports extensively on the host adapter hardware configuration, including the synchronous transfer parameters - negotiated with each target device. In addition, the driver tests the - hardware interrupt configuration to verify that interrupts are actually - delivered correctly to the interrupt handler. This should catch a high - percentage of PCI motherboard configuration errors early, because when the - host adapter is probed successfully, most of the remaining problems appear to - be related to interrupts. Most often, any remaining hardware problems are - related to the specific configuration of devices on the SCSI bus, and the - quality of cabling and termination used. Finally, this BusLogic driver - should never incorrectly attempt to support an Adaptec 154x Host Adapter. + requested and negotiated with each target device. AutoSCSI settings for + Synchronous Negotiation, Wide Negotiation, and Disconnect/Reconnect are + reported for each target device, as well as the status of Tagged Queuing and + Error Recovery. If the same setting is in effect for all target devices, + then a single word or phrase is used; otherwise, a letter is provided for + each target device to indicate the individual status. The following examples + should clarify this reporting format: + + Synchronous Negotiation: Ultra + + Synchronous negotiation is enabled for all target devices and the host + adapter will attempt to negotiate for 20.0 mega-transfers/second. + + Synchronous Negotiation: Fast + + Synchronous negotiation is enabled for all target devices and the host + adapter will attempt to negotiate for 10.0 mega-transfers/second. + + Synchronous Negotiation: Slow + + Synchronous negotiation is enabled for all target devices and the host + adapter will attempt to negotiate for 5.0 mega-transfers/second. + + Synchronous Negotiation: Disabled + + Synchronous negotiation is disabled and all target devices are limited to + asynchronous operation. + + Synchronous Negotiation: UFSNUUU#UUUUUUUU + + Synchronous negotiation to Ultra speed is enabled for target devices 0 + and 4 through 15, to Fast speed for target device 1, to Slow speed for + target device 2, and is not permitted to target device 3. The host + adapter's SCSI ID is represented by the "#". + + The status of Wide Negotiation, Disconnect/Reconnect, and Tagged Queuing + are reported as "Enabled", Disabled", or a sequence of "Y" and "N" letters. + + The Error Recovery option is reported as "Default", "Hard Reset", + "Bus Device Reset", "None" or a sequence of "D", "H", "B", and "N" letters. o Performance Features @@ -103,16 +143,15 @@ addition, BusLogic's Strict Round Robin Mode is used to optimize host adapter performance, and scatter/gather I/O can support as many segments as can be effectively utilized by the Linux I/O subsystem. Control over the use of - tagged queuing for each target device as well as selection of the tagged - queue depth is available from the kernel command line. By default, the queue - depth is automatically determined based on the number, type, speed, and - capabilities of the target devices found. In addition, tagged queuing is - automatically disabled whenever the host adapter firmware version is known - not to implement it correctly, or whenever a tagged queue depth of 1 is - selected. Tagged queuing is also disabled for individual target devices if - disconnect/reconnect is disabled for that device. In performance testing, - sustained disk writes of 7.3MB per second have been observed to a /dev/sd - device. + tagged queuing for each target device as well as individual selection of the + tagged queue depth is available through driver options provided on the kernel + command line or at module initialization time. By default, the queue depth + is determined automatically based on the host adapter's total queue depth and + the number, type, speed, and capabilities of the target devices found. In + addition, tagged queuing is automatically disabled whenever the host adapter + firmware version is known not to implement it correctly, or whenever a tagged + queue depth of 1 is selected. Tagged queuing is also disabled for individual + target devices if disconnect/reconnect is disabled for that device. o Robustness Features @@ -121,15 +160,15 @@ a selection is made between a full host adapter hard reset and SCSI bus reset versus sending a bus device reset message to the individual target device based on the recommendation of the SCSI subsystem. Error recovery strategies - are selectable from the kernel command line individually for each target - device, and also include sending a bus device reset to the specific target - device associated with the command being reset, as well as suppressing error + are selectable through driver options individually for each target device, + and also include sending a bus device reset to the specific target device + associated with the command being reset, as well as suppressing error recovery entirely to avoid perturbing an improperly functioning device. If the bus device reset error recovery strategy is selected and sending a bus device reset does not restore correct operation, the next command that is reset will force a full host adapter hard reset and SCSI bus reset. SCSI bus resets caused by other devices and detected by the host adapter are also - handled by issuing a hard reset to the host adapter and re-initialization. + handled by issuing a soft reset to the host adapter and re-initialization. Finally, if tagged queuing is active and more than one command reset occurs in a 10 minute interval, or if a command reset occurs within the first 10 minutes of operation, then tagged queuing will be disabled for that target @@ -138,15 +177,6 @@ lock up or crash, and thereby allowing a clean shutdown and restart after the offending component is removed. -o Extensive Testing - - This driver has undergone extensive testing and improvement over a period of - several months, and is routinely being used on heavily loaded systems. Over - 300 people retrieved the driver during the beta test period. In addition to - testing in normal system operation, error recovery tests have been performed - to verify proper system recovery in the case of simulated dropped interrupts, - external SCSI bus resets, and SCSI command errors due to bad CD-ROM media. - o PCI Configuration Support On PCI systems running kernels compiled with PCI BIOS support enabled, this @@ -159,8 +189,8 @@ o /proc File System Support - Copies of the host adapter configuration information together with data - transfer and error recovery statistics are now available through the + Copies of the host adapter configuration information together with updated + data transfer and error recovery statistics are available through the /proc/scsi/BusLogic/ interface. o Shared Interrupts Support @@ -168,16 +198,6 @@ On systems that support shared interrupts, any number of BusLogic Host Adapters may share the same interrupt request channel. -o Wide SCSI Support - - All BusLogic MultiMaster SCSI Host Adapters share a common programming - interface, except for the inevitable improvements and extensions as new - models are released, so support for Wide SCSI data transfer has automatically - been available without explicit driver support. When used with Linux 2.0.x, - this driver adds explicit support for up to 15 target devices and 64 logical - units per target device, to fully exploit the capabilities of the newest - BusLogic Wide SCSI Host Adapters. - SUPPORTED HOST ADAPTERS @@ -188,16 +208,21 @@ FlashPoint Series PCI Host Adapters: -FlashPoint LT (BT-930) Ultra SCSI-2 -FlashPoint DL (BT-932) Dual Channel Ultra SCSI-2 -FlashPoint LW (BT-950) Wide Ultra SCSI-2 -FlashPoint DW (BT-952) Dual Channel Wide Ultra SCSI-2 +FlashPoint LT (BT-930) Ultra SCSI-3 +FlashPoint LT (BT-930R) Ultra SCSI-3 with RAIDPlus +FlashPoint LT (BT-920) Ultra SCSI-3 (BT-930 without BIOS) +FlashPoint DL (BT-932) Dual Channel Ultra SCSI-3 +FlashPoint DL (BT-932R) Dual Channel Ultra SCSI-3 with RAIDPlus +FlashPoint LW (BT-950) Wide Ultra SCSI-3 +FlashPoint LW (BT-950R) Wide Ultra SCSI-3 with RAIDPlus +FlashPoint DW (BT-952) Dual Channel Wide Ultra SCSI-3 +FlashPoint DW (BT-952R) Dual Channel Wide Ultra SCSI-3 with RAIDPlus MultiMaster "W" Series Host Adapters: -BT-948 PCI Ultra SCSI-2 -BT-958 PCI Wide Ultra SCSI-2 -BT-958D PCI Wide Differential Ultra SCSI-2 +BT-948 PCI Ultra SCSI-3 +BT-958 PCI Wide Ultra SCSI-3 +BT-958D PCI Wide Differential Ultra SCSI-3 MultiMaster "C" Series Host Adapters: @@ -231,6 +256,39 @@ AMI FastDisk Host Adapters that are true BusLogic MultiMaster clones are also supported by this driver. +BusLogic SCSI Host Adapters are available packaged both as bare boards and as +retail kits. The BT- model numbers above refer to the bare board packaging. +The retail kit model numbers are found by replacing BT- with KT- in the above +list. The retail kit includes the bare board and manual as well as cabling and +driver media and documentation that are not provided with bare boards. + + + FLASHPOINT INSTALLATION NOTES + +o RAIDPlus Support + + FlashPoint Host Adapters now include RAIDPlus, Mylex's bootable software + RAID. RAIDPlus is not supported on Linux, and there are no plans to support + it. The MD driver in Linux 2.0 provides for concatenation (LINEAR) and + striping (RAID-0), and support for mirroring (RAID-1), fixed parity (RAID-4), + and distributed parity (RAID-5) is available separately. The built-in Linux + RAID support is generally more flexible and is expected to perform better + than RAIDPlus, so there is little impetus to include RAIDPlus support in the + BusLogic driver. + +o Enabling UltraSCSI Transfers + + FlashPoint Host Adapters ship with their configuration set to "Factory + Default" settings that are conservative and do not allow for UltraSCSI speed + to be negotiated. This results in fewer problems when these host adapters + are installed in systems with cabling or termination that is not sufficient + for UltraSCSI operation, or where existing SCSI devices do not properly + respond to synchronous transfer negotiation for UltraSCSI speed. AutoSCSI + may be used to load "Optimum Performance" settings which allow UltraSCSI + speed to be negotiated with all devices, or UltraSCSI speed can be enabled on + an individual basis. It is recommended that SCAM be manually disabled after + the "Optimum Performance" settings are loaded. + BT-948/958/958D INSTALLATION NOTES @@ -284,113 +342,254 @@ so as to recognize the host adapters in the same order as they are enumerated by the host adapter's BIOS. -o Mega-Transfers/Second +o Enabling UltraSCSI Transfers + + The BT-948/958/958D ship with their configuration set to "Factory Default" + settings that are conservative and do not allow for UltraSCSI speed to be + negotiated. This results in fewer problems when these host adapters are + installed in systems with cabling or termination that is not sufficient for + UltraSCSI operation, or where existing SCSI devices do not properly respond + to synchronous transfer negotiation for UltraSCSI speed. AutoSCSI may be + used to load "Optimum Performance" settings which allow UltraSCSI speed to be + negotiated with all devices, or UltraSCSI speed can be enabled on an + individual basis. It is recommended that SCAM be manually disabled after the + "Optimum Performance" settings are loaded. + + + DRIVER OPTIONS + +BusLogic Driver Options may be specified either via the Linux Kernel Command +Line or via the Loadable Kernel Module Installation Facility. Driver Options +for multiple host adapters may be specified either by separating the option +strings by a semicolon, or by specifying multiple "BusLogic=" strings on the +command line. Individual option specifications for a single host adapter are +separated by commas. The Probing and Debugging Options apply to all host +adapters whereas the remaining options apply individually only to the +selected host adapter. + +The BusLogic Driver Probing Options comprise the following: + +IO: + + The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI + MultiMaster Host Adapter. If neither "IO:" nor "NoProbeISA" options are + specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses + will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134). Multiple + "IO:" options may be specified to precisely determine the I/O Addresses to + be probed, but the probe order will always follow the standard list. + +NoProbe + + The "NoProbe" option disables all probing and therefore no BusLogic Host + Adapters will be detected. + +NoProbeISA + + The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O + Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters + will be detected. - The driver reports on the synchronous transfer parameters negotiated between - the host adapter and target devices in units of "mega-transfers/second". For - wide devices, the unit of transfer is 16 bits if wide negotiation has been - successfully completed. Therefore, the total transfer rate to wide devices - will generally be twice the synchronous tranfer rate reported by the driver. +NoProbePCI + The "NoProbePCI" options disables the interrogation of PCI Configuration + Space and therefore only ISA Multimaster Host Adapters will be detected, as + well as PCI Multimaster Host Adapters that have their ISA Compatible I/O + Port set to "Primary" or "Alternate". - COMMAND LINE OPTIONS +NoSortPCI -Many features of this driver are configurable by specification of appropriate -kernel command line options. A full description of the command line options -may be found in the comments before BusLogic_Setup in the kernel source code -file "BusLogic.c". The following examples may be useful as a starting point: + The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be + enumerated in the order provided by the PCI BIOS, ignoring any setting of + the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option. - "BusLogic=NoProbe" +MultiMasterFirst - No probing of any kind is to be performed, and hence no BusLogic Host - Adapters will be detected. + The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed + before FlashPoint Host Adapters. By default, if both FlashPoint and PCI + MultiMaster Host Adapters are present, this driver will probe for + FlashPoint Host Adapters first unless the BIOS primary disk is controlled + by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host + Adapters will be probed first. - "BusLogic=NoProbeISA" +FlashPointFirst - No probing of the standard ISA I/O Addresses will be done, and hence only - PCI Host Adapters will be detected. + The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed + before MultiMaster Host Adapters. - "BusLogic=NoProbePCI" +The BusLogic Driver Tagged Queuing Options allow for explicitly specifying +the Queue Depth and whether Tagged Queuing is permitted for each Target +Device (assuming that the Target Device supports Tagged Queuing). The Queue +Depth is the number of SCSI Commands that are allowed to be concurrently +presented for execution (either to the Host Adapter or Target Device). Note +that explicitly enabling Tagged Queuing may lead to problems; the option to +enable or disable Tagged Queuing is provided primarily to allow disabling +Tagged Queuing on Target Devices that do not implement it correctly. The +following options are available: - No interrogation of PCI Configuration Space will be made, and hence only - ISA Multimaster Host Adapters will be detected, as well as PCI Multimaster - Host Adapters that have their ISA Compatible I/O Port set to "Primary" or - "Alternate". +QueueDepth: - "BusLogic=NoSortPCI" + The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all + Target Devices that support Tagged Queuing. If no Queue Depth option is + provided, the Queue Depth will be determined automatically based on the + Host Adapter's Total Queue Depth and the number, type, speed, and + capabilities of the detected Target Devices. For Host Adapters that + require ISA Bounce Buffers, the Queue Depth is automatically set by default + to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA + Bounce Buffer memory. Target Devices that do not support Tagged Queuing + always use a Queue Depth of BusLogic_UntaggedQueueDepth. - PCI MultiMaster Host Adapters will be enumerated in the order provided by - the PCI BIOS, ignoring any setting of the AutoSCSI "Use Bus And Device # - For PCI Scanning Seq." option. +QueueDepth:[,...] - "BusLogic=MultiMasterFirst" + The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth + individually for each Target Device. If an is omitted, the + associated Target Device will have its Queue Depth selected automatically. - By default, if both FlashPoint and PCI MultiMaster Host Adapters are - present, this driver will probe for FlashPoint Host Adapters first unless - the BIOS primary disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will be probed first. - This option forces MultiMaster Host Adapters to be probed first. +TaggedQueuing:Default - "BusLogic=FlashPointFirst" + The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing + based on the firmware version of the BusLogic Host Adapter and based on + whether the Queue Depth allows queuing multiple commands. - By default, if both FlashPoint and PCI MultiMaster Host Adapters are - present, this driver will probe for FlashPoint Host Adapters first unless - the BIOS primary disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will be probed first. - This option forces FlashPoint Host Adapters to be probed first. +TaggedQueuing:Enable - "BusLogic=0x330" + The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for + all Target Devices on this Host Adapter, overriding any limitation that + would otherwise be imposed based on the Host Adapter firmware version. - This command line limits probing to the single I/O port at 0x330. +TaggedQueuing:Disable - "BusLogic=0,1" + The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing + for all Target Devices on this Host Adapter. - This command line selects default probing and a tagged queue depth of 1 - which also disables tagged queuing. It may be useful if problems arise - during installation on a system with a flaky SCSI configuration. In cases - of a marginal SCSI configuration it may also be beneficial to disable fast - transfers and/or synchronous negotiation using AutoSCSI on FlashPoint and - "W" and "C" series MultiMaster host adapters. Disconnect/reconnect may - also be disabled for fast devices such as disk drives, but should not be - disabled for tape drives or other devices where a single command may take - over a second to execute. +TaggedQueuing: - "BusLogic=0,0,30" + The "TaggedQueuing:" or "TQ:" option controls + Tagged Queuing individually for each Target Device. is a + sequence of "Y", "N", and "X" characters. "Y" enables Tagged Queuing, "N" + disables Tagged Queuing, and "X" accepts the default based on the firmware + version. The first character refers to Target Device 0, the second to + Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters + does not cover all the Target Devices, unspecified characters are assumed + to be "X". - This command line selects default probing and automatic tagged queue depth - selection, but changes the bus settle time to 30 seconds. It may be useful - with SCSI devices that take an unusually long time to become ready to - accept commands after a SCSI bus reset. Some tape drives will not respond - properly immediately after a SCSI bus reset, especially if a tape is - present in the drive. +The BusLogic Driver Error Recovery Option allows for explicitly specifying +the Error Recovery action to be performed when BusLogic_ResetCommand is +called due to a SCSI Command failing to complete successfully. The following +options are available: - "BusLogic=TQ:Disable" +ErrorRecovery:Default - This command line selects default probing and disables tagged queuing. + The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard + Reset and Bus Device Reset options based on the recommendation of the SCSI + Subsystem. - "BusLogic=0,15,TQ:N" +ErrorRecovery:HardReset - This command line selects a tagged queue depth of 15 and disables tagged - queuing for target 0, while allowing tagged queuing for all other target - devices. + The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host + Adapter Hard Reset which also causes a SCSI Bus Reset. -Note that limiting the tagged queue depth or disabling tagged queuing can -substantially impact performance. +ErrorRecovery:BusDeviceReset + The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send + a Bus Device Reset message to the individual Target Device causing the + error. If Error Recovery is again initiated for this Target Device and no + SCSI Command to this Target Device has completed successfully since the Bus + Device Reset message was sent, then a Hard Reset will be attempted. - INSTALLATION +ErrorRecovery:None -This distribution was prepared for Linux kernel version 2.0.30, but should be -compatible with 2.0.4 or any later 2.0 series kernel if BusLogic.patch is also -applied. + The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery. + This option should only be selected if a SCSI Bus Reset or Bus Device Reset + will cause the Target Device or a critical operation to suffer a complete + and unrecoverable failure. + +ErrorRecovery: + + The "ErrorRecovery:" or "ER:" option controls + Error Recovery individually for each Target Device. is a + sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H" + selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None. + The first character refers to Target Device 0, the second to Target Device + 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not + cover all the possible Target Devices, unspecified characters are assumed + to be "D". + +The BusLogic Driver Miscellaneous Options comprise the following: + +BusSettleTime: + + The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in + seconds. The Bus Settle Time is the amount of time to wait between a Host + Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI + Commands. If unspecified, it defaults to BusLogic_DefaultBusSettleTime. + +InhibitTargetInquiry + + The "InhibitTargetInquiry" option inhibits the execution of an Inquire + Target Devices or Inquire Installed Devices command on MultiMaster Host + Adapters. This may be necessary with some older Target Devices that do not + respond correctly when Logical Units above 0 are addressed. + +The BusLogic Driver Debugging Options comprise the following: + +TraceProbe + + The "TraceProbe" option enables tracing of Host Adapter Probing. + +TraceHardwareReset + + The "TraceHardwareReset" option enables tracing of Host Adapter Hardware + Reset. + +TraceConfiguration + + The "TraceConfiguration" option enables tracing of Host Adapter + Configuration. + +TraceErrors + + The "TraceErrors" option enables tracing of SCSI Commands that return an + error from the Target Device. The CDB and Sense Data will be printed for + each SCSI Command that fails. + +Debug + + The "Debug" option enables all debugging options. + +The following examples demonstrate setting the Queue Depth for Target Devices +1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target +Devices on the second host adapter to 31, and the Bus Settle Time on the +second host adapter to 30 seconds. + +Linux Kernel Command Line: + + linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30 + +LILO Linux Boot Loader (in /etc/lilo.conf): + + append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30" + +INSMOD Loadable Kernel Module Installation Facility: + + insmod BusLogic.o \ + 'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"' + +NOTE: Module Utilities 2.1.71 or later is required for correct parsing + of driver options containing commas. + + + DRIVER INSTALLATION + +This distribution was prepared for Linux kernel version 2.0.33, but should be +compatible with 2.0.4 or any later 2.0 series kernel. To install the new BusLogic SCSI driver, you may use the following commands, replacing "/usr/src" with wherever you keep your Linux kernel source tree: cd /usr/src - tar -xvzf BusLogic-2.0.10.tar.gz + tar -xvzf BusLogic-2.0.11.tar.gz mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi - patch -p < BusLogic.patch # Only for kernels prior to 2.0.30 + patch -p < BusLogic.patch cd linux make config make depend @@ -398,11 +597,6 @@ Then install "arch/i386/boot/zImage" as your standard kernel, run lilo if appropriate, and reboot. - -Be sure to answer "y" to the "BusLogic SCSI support" query during the "make -config" step. If your system was already configured for the old BusLogic -driver or for an older version of this driver, you may omit the "make config" -step above. BUSLOGIC ANNOUNCEMENTS MAILING LIST diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/README.Mylex linux/drivers/scsi/README.Mylex --- v2.1.86/linux/drivers/scsi/README.Mylex Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/README.Mylex Sat Jan 31 02:00:00 1998 @@ -0,0 +1,6 @@ +Please see the file README.BusLogic for information about Linux support for +Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters. + +The Mylex DAC960 PCI RAID Controllers are not supported at the present time, +but work on a Linux driver for the DAC960 is in progress. Please consult +http://www.dandelion.com/Linux/ for further information on the DAC960 driver. diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.1.86/linux/drivers/scsi/hosts.h Fri Feb 6 15:33:40 1998 +++ linux/drivers/scsi/hosts.h Thu Feb 12 16:25:04 1998 @@ -371,7 +371,13 @@ void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); - unsigned long hostdata[0]; /* Used for storage of host specific stuff */ + /* + * We should ensure that this is aligned, both for better performance + * and also because some compilers (m68k) don't automatically force + * alignment to a 4-byte boundary. + */ + unsigned long hostdata[0] /* Used for storage of host specific stuff */ + __attribute__ ((aligned (4))); }; extern struct Scsi_Host * scsi_hostlist; diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/ibmmca.h linux/drivers/scsi/ibmmca.h --- v2.1.86/linux/drivers/scsi/ibmmca.h Wed Feb 4 11:36:00 1998 +++ linux/drivers/scsi/ibmmca.h Thu Feb 12 16:25:04 1998 @@ -19,29 +19,29 @@ extern struct proc_dir_entry proc_scsi_ibmmca; /*initialization for Scsi_host_template type */ -#define IBMMCA { \ - NULL, /*next*/ \ - NULL, /*usage_count*/ \ - &proc_scsi_ibmmca, /*proc_dir*/ \ - ibmmca_proc_info, /*proc info fn*/ \ - "IBMMCA", /*name*/ \ - ibmmca_detect, /*detect fn*/ \ - ibmmca_release, /*release fn*/ \ - NULL, /*info fn*/ \ - ibmmca_command, /*command fn*/ \ - ibmmca_queuecommand, /*queuecommand fn*/ \ - ibmmca_abort, /*abort fn*/ \ - ibmmca_reset, /*reset fn*/ \ - NULL, /*slave_attach fn*/ \ - ibmmca_biosparam, /*bios fn*/ \ - 16, /*can_queue*/ \ - 7, /*set by detect*/ \ - 16, /*sg_tablesize*/ \ - 1, /*cmd_per_lun*/ \ - 0, /*present*/ \ - 0, /*unchecked_isa_dma*/ \ - ENABLE_CLUSTERING /*use_clustering*/ \ - } +/* + * 2/8/98 + * Note to maintainer of IBMMCA. Do not change this initializer back to + * the old format. Please ask eric@andante.jic.com if you have any questions + * about this, but it will break things in the future. + */ +#define IBMMCA { \ + proc_dir: &proc_scsi_ibmmca, /*proc_dir*/ \ + proc_info: ibmmca_proc_info, /*proc info fn*/ \ + name: "IBMMCA", /*name*/ \ + detect: ibmmca_detect, /*detect fn*/ \ + release: ibmmca_release, /*release fn*/ \ + command: ibmmca_command, /*command fn*/ \ + queuecommand: ibmmca_queuecommand, /*queuecommand fn*/ \ + abort: ibmmca_abort, /*abort fn*/ \ + reset: ibmmca_reset, /*reset fn*/ \ + bios_param: ibmmca_biosparam, /*bios fn*/ \ + can_queue: 16, /*can_queue*/ \ + this_id: 7, /*set by detect*/ \ + sg_tablesize: 16, /*sg_tablesize*/ \ + cmd_per_lun: 1, /*cmd_per_lun*/ \ + use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \ + } #endif /* _IBMMCA_H */ diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.1.86/linux/drivers/scsi/pci2000.c Wed Nov 5 12:59:49 1997 +++ linux/drivers/scsi/pci2000.c Thu Feb 12 15:42:55 1998 @@ -653,7 +653,7 @@ #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = PCI2220I; +Scsi_Host_Template driver_template = PCI2000; #include "scsi_module.c" #endif diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.86/linux/drivers/scsi/scsi.h Fri Feb 6 15:33:40 1998 +++ linux/drivers/scsi/scsi.h Thu Feb 12 16:22:17 1998 @@ -685,7 +685,7 @@ #define INIT_SCSI_REQUEST \ if (!CURRENT) { \ CLEAR_INTR; \ - restore_flags(flags); \ + spin_unlock_irqrestore(¤t_lock,flags); \ return; \ } \ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \ diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.1.86/linux/drivers/scsi/scsi_error.c Mon Jan 19 22:13:17 1998 +++ linux/drivers/scsi/scsi_error.c Thu Feb 12 16:25:04 1998 @@ -1785,7 +1785,7 @@ * This needs to be attached to task[0] instead. */ - sigfillset(¤t->blocked); + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); current->fs->umask = 0; /* diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.86/linux/drivers/scsi/sd.c Sat Jan 10 10:50:07 1998 +++ linux/drivers/scsi/sd.c Thu Feb 12 16:25:04 1998 @@ -91,7 +91,7 @@ { if( disknum <= 26 ) { - sprintf(buffer, "sd%c", 'a' + (disknum >> 4)); + sprintf(buffer, "sd%c", 'a' + disknum); } else { @@ -101,8 +101,8 @@ * For larger numbers of disks, we need to go to a new * naming scheme. */ - min1 = (disknum >> 4) / 26; - min2 = (disknum >> 4) % 26; + min1 = disknum / 26; + min2 = disknum % 26; sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2); } } @@ -516,11 +516,11 @@ unsigned long flags; int flag = 0; - save_flags(flags); while (1==1){ - cli(); + spin_lock_irqsave(¤t_lock, flags); + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - restore_flags(flags); + spin_unlock_irqrestore(¤t_lock, flags); return; } @@ -535,6 +535,7 @@ */ if( SDev->host->in_recovery ) { + spin_unlock_irqrestore(¤t_lock, flags); return; } @@ -554,6 +555,7 @@ */ if( SDev->removable && !in_interrupt() ) { + spin_unlock(¤t_lock); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); /* scsi_ioctl may allow CURRENT to change, so start over. */ SDev->was_reset = 0; @@ -585,7 +587,7 @@ * Using a "sti()" gets rid of the latency problems but causes * race conditions and crashes. */ - restore_flags(flags); + spin_unlock_irqrestore(¤t_lock, flags); /* This is a performance enhancement. We dig down into the request * list and try to find a queueable request (i.e. device not busy, @@ -603,7 +605,7 @@ if (!SCpnt && sd_template.nr_dev > 1){ struct request *req1; req1 = NULL; - cli(); + spin_lock_irqsave(¤t_lock, flags); req = CURRENT; while(req){ SCpnt = scsi_request_queueable(req, @@ -618,7 +620,7 @@ else req1->next = req->next; } - restore_flags(flags); + spin_unlock_irqrestore(¤t_lock, flags); } if (!SCpnt) return; /* Could not find anything to do */ diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.86/linux/drivers/scsi/sr.c Thu Jan 8 20:35:43 1998 +++ linux/drivers/scsi/sr.c Thu Feb 12 16:25:04 1998 @@ -761,7 +761,13 @@ if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2; - if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) + /* + * 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) { diff -u --recursive --new-file v2.1.86/linux/fs/adfs/super.c linux/fs/adfs/super.c --- v2.1.86/linux/fs/adfs/super.c Tue Jan 20 16:44:58 1998 +++ linux/fs/adfs/super.c Wed Feb 11 16:19:56 1998 @@ -331,11 +331,7 @@ #ifdef MODULE int init_module (void) { - int status; - - if ((status = init_adfs_fs()) == 0) - register_symtab(0); - return status; + return (init_adfs_fs()); } void cleanup_module (void) diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c --- v2.1.86/linux/fs/ufs/ufs_dir.c Sat Nov 8 09:52:02 1997 +++ linux/fs/ufs/ufs_dir.c Thu Feb 12 16:27:15 1998 @@ -8,6 +8,9 @@ * * swab support by Francois-Rene Rideau 19970406 * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . */ #include @@ -28,17 +31,18 @@ struct ufs_direct * de; struct super_block * sb; int de_reclen; - __u32 s_flags, bytesex; + __u32 flags; - /* Isn't that already done but the upper layer??? */ + /* Isn't that already done in the upper layer??? + * the VFS layer really needs some explicit documentation! + */ if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; sb = inode->i_sb; - s_flags = sb->u.ufs_sb.s_flags; - bytesex = s_flags & UFS_BYTESEX; + flags = sb->u.ufs_sb.s_flags; - if (s_flags & UFS_DEBUG) { + if (flags & UFS_DEBUG) { printk("ufs_readdir: ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos); ufs_print_inode(inode); @@ -92,20 +96,23 @@ && offset < sb->s_blocksize) { de = (struct ufs_direct *) (bh->b_data + offset); /* XXX - put in a real ufs_check_dir_entry() */ - if ((de->d_reclen == 0) || (de->d_namlen == 0)) { + if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) { /* SWAB16() was unneeded -- compare to 0 */ - filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; + filp->f_pos = (filp->f_pos & + (sb->s_blocksize - 1)) + + sb->s_blocksize; brelse(bh); return stored; } -#if 0 +#if 0 /* XXX */ if (!ext2_check_dir_entry ("ext2_readdir", inode, de, /* XXX - beware about de having to be swabped somehow */ bh, offset)) { /* On error, skip the f_pos to the next block. */ - filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) - + sb->s_blocksize; + filp->f_pos = (filp->f_pos & + (sb->s_blocksize - 1)) + + sb->s_blocksize; brelse (bh); return stored; } @@ -121,11 +128,12 @@ * during the copy operation. */ unsigned long version = inode->i_version; - if (s_flags & UFS_DEBUG) { + if (flags & UFS_DEBUG) { printk("ufs_readdir: filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)); } - error = filldir(dirent, de->d_name, SWAB16(de->d_namlen), filp->f_pos, SWAB32(de->d_ino)); + error = filldir(dirent, de->d_name, NAMLEN(de), + filp->f_pos, SWAB32(de->d_ino)); if (error) break; if (version != inode->i_version) diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c --- v2.1.86/linux/fs/ufs/ufs_inode.c Tue Oct 21 05:26:13 1997 +++ linux/fs/ufs/ufs_inode.c Thu Feb 12 16:27:15 1998 @@ -9,8 +9,18 @@ * Clean swab support on 19970406 * by Francois-Rene Rideau * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . + * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen . */ +#undef DEBUG_UFS_INODE +/*#define DEBUG_UFS_INODE 1*/ +/* Uncomment the line above when hacking ufs inode code */ + #include #include #include @@ -25,29 +35,30 @@ inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count); printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x" " 0x%x 0x%x 0x%x 0x%x>\n", - inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1], - inode->u.ufs_i.i_data[2], inode->u.ufs_i.i_data[3], - inode->u.ufs_i.i_data[4], inode->u.ufs_i.i_data[5], - inode->u.ufs_i.i_data[6], inode->u.ufs_i.i_data[7], - inode->u.ufs_i.i_data[8], inode->u.ufs_i.i_data[9], - inode->u.ufs_i.i_data[10], inode->u.ufs_i.i_data[11]); + inode->u.ufs_i.i_u1.i_data[0], inode->u.ufs_i.i_u1.i_data[1], + inode->u.ufs_i.i_u1.i_data[2], inode->u.ufs_i.i_u1.i_data[3], + inode->u.ufs_i.i_u1.i_data[4], inode->u.ufs_i.i_u1.i_data[5], + inode->u.ufs_i.i_u1.i_data[6], inode->u.ufs_i.i_u1.i_data[7], + inode->u.ufs_i.i_u1.i_data[8], inode->u.ufs_i.i_u1.i_data[9], + inode->u.ufs_i.i_u1.i_data[10], inode->u.ufs_i.i_u1.i_data[11]); printk(" gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n", inode->u.ufs_i.i_gen, - inode->u.ufs_i.i_data[UFS_IND_BLOCK], - inode->u.ufs_i.i_data[UFS_DIND_BLOCK], - inode->u.ufs_i.i_data[UFS_TIND_BLOCK]); + inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK], + inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK], + inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]); } -#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_data[(nr)]) +#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_u1.i_data[(nr)]) static inline int block_bmap (struct inode *inode, int block, int nr) { struct buffer_head *bh; int tmp; - __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; + __u32 flags = inode->i_sb->u.ufs_sb.s_flags; /* XXX Split in fsize big blocks (Can't bread 8Kb). */ tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2); - bh = bread (inode->i_dev, block + tmp, inode->i_sb->u.ufs_sb.s_fsize); + bh = bread (inode->i_dev, inode->i_sb->u.ufs_sb.s_blockbase + block + + tmp, inode->i_sb->s_blocksize); if (!bh) return 0; nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2; @@ -75,13 +86,16 @@ return 0; } if (lbn < UFS_NDADDR) - return ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff); + return (inode->i_sb->u.ufs_sb.s_blockbase + + ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff)); lbn -= UFS_NDADDR; if (lbn < addr_per_block) { i = inode_bmap (inode, UFS_IND_BLOCK); if (!i) return 0; - return ufs_dbn (inode->i_sb, block_bmap (inode, i, lbn), boff); + return (inode->i_sb->u.ufs_sb.s_blockbase + + ufs_dbn (inode->i_sb, + block_bmap (inode, i, lbn), boff)); } lbn -= addr_per_block; if (lbn < (1 << (addr_per_block_bits * 2))) { @@ -91,9 +105,10 @@ i = block_bmap (inode, i, lbn >> addr_per_block_bits); if (!i) return 0; - return ufs_dbn (inode->i_sb, + return (inode->i_sb->u.ufs_sb.s_blockbase + + ufs_dbn (inode->i_sb, block_bmap (inode, i, lbn & (addr_per_block-1)), - boff); + boff)); } lbn -= (1 << (addr_per_block_bits * 2)); i = inode_bmap (inode, UFS_TIND_BLOCK); @@ -106,8 +121,9 @@ (lbn >> addr_per_block_bits) & (addr_per_block - 1)); if (!i) return 0; - return ufs_dbn (inode->i_sb, - block_bmap (inode, i, lbn & (addr_per_block-1)), boff); + return (inode->i_sb->u.ufs_sb.s_blockbase + + ufs_dbn (inode->i_sb, + block_bmap (inode, i, lbn & (addr_per_block-1)), boff)); } /* XXX - ufs_read_inode is a mess */ @@ -116,28 +132,30 @@ struct super_block * sb; struct ufs_inode * ufsip; struct buffer_head * bh; - __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; + __u32 flags = inode->i_sb->u.ufs_sb.s_flags; sb = inode->i_sb; if (ufs_ino_ok(inode)) { - printk("ufs_read_inode: bad inum %lu", inode->i_ino); + printk("ufs_read_inode: bad inum %lu\n", inode->i_ino); return; } -#if 0 +#ifdef DEBUG_UFS_INODE printk("ufs_read_inode: ino %lu cg %u cgino %u ipg %u inopb %u\n", inode->i_ino, ufs_ino2cg(inode), (inode->i_ino%sb->u.ufs_sb.s_inopb), sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb); #endif bh = bread(inode->i_dev, + inode->i_sb->u.ufs_sb.s_blockbase + ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + - (inode->i_ino%sb->u.ufs_sb.s_ipg)/(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag), - BLOCK_SIZE); + (inode->i_ino%sb->u.ufs_sb.s_ipg)/ + (sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag), + sb->s_blocksize); if (!bh) { - printk("ufs_read_inode: can't read inode %lu from dev %d/%d", + printk("ufs_read_inode: can't read inode %lu from dev %d/%d\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); return; } @@ -176,23 +194,21 @@ * random users can't get at these files, since they get dynamically * "chown()ed" to root. */ - if (SWAB16(ufsip->ui_suid) == UFS_USEEFT) { - /* EFT */ + if (UFS_UID(ufsip) >= UFS_USEEFT) { inode->i_uid = 0; printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n", - SWAB32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), - inode->i_uid); + UFS_UID(ufsip), inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev), inode->i_uid); } else { - inode->i_uid = SWAB16(ufsip->ui_suid); + inode->i_uid = UFS_UID(ufsip); } - if (SWAB16(ufsip->ui_sgid) == UFS_USEEFT) { - /* EFT */ + if (UFS_GID(ufsip) >= UFS_USEEFT) { inode->i_gid = 0; printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n", - SWAB32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), - inode->i_gid); + UFS_GID(ufsip), inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev), inode->i_gid); } else { - inode->i_gid = SWAB16(ufsip->ui_sgid); + inode->i_gid = UFS_GID(ufsip); } /* @@ -249,13 +265,19 @@ S_ISLNK(inode->i_mode)) { int i; - for (i = 0; i < UFS_NDADDR; i++) { - inode->u.ufs_i.i_data[i] = SWAB32(ufsip->ui_db[i]); - } - for (i = 0; i < UFS_NINDIR; i++) { - inode->u.ufs_i.i_data[UFS_IND_BLOCK + i] = - SWAB32(ufsip->ui_ib[i]); - } + if (inode->i_blocks) { + for (i = 0; i < UFS_NDADDR; i++) { + inode->u.ufs_i.i_u1.i_data[i] = + SWAB32(ufsip->ui_u2.ui_addr.ui_db[i]); + } + for (i = 0; i < UFS_NINDIR; i++) { + inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK + i] = + SWAB32(ufsip->ui_u2.ui_addr.ui_ib[i]); + } + } else /* fast symlink */ { + memcpy(inode->u.ufs_i.i_u1.i_symlink, + ufsip->ui_u2.ui_symlink, 60); + } } /* KRR - I need to check the SunOS header files, but for the time @@ -265,17 +287,15 @@ * the code. */ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_db); + inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_u2.ui_addr.ui_db); } - /* XXX - implement fast and slow symlinks */ - inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags); inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */ - inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_shadow); /* XXX */ - inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_uid); - inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_gid); - inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_oeftflag); + inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_u3.ui_sun.ui_shadow); /* XXX */ + inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_u3.ui_sun.ui_uid); + inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_u3.ui_sun.ui_gid); + inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_u3.ui_sun.ui_oeftflag); brelse(bh); diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c --- v2.1.86/linux/fs/ufs/ufs_namei.c Thu Dec 4 01:27:48 1997 +++ linux/fs/ufs/ufs_namei.c Thu Feb 12 16:27:15 1998 @@ -9,6 +9,9 @@ * Clean swab support by Francois-Rene Rideau 19970406 * Ported to 2.1.62 by Francois-Rene Rideau 19971109 * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . */ #include @@ -19,18 +22,19 @@ /* * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. * stolen from ext2fs + * NOTE2: flags *is* used, through this is hidden by macros like SWAB16. */ -static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 bytesex) +static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 flags) { if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */ return 0; /* * "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (SWAB16(d->d_namlen) == 1) && (d->d_name[0] == '.') && + if (!len && (NAMLEN(d) == 1) && (d->d_name[0] == '.') && (d->d_name[1] == '\0')) return 1; - if (len != SWAB16(d->d_namlen)) + if (len != NAMLEN(d)) return 0; return !memcmp(name, d->d_name, len); } @@ -38,89 +42,88 @@ int ufs_lookup (struct inode *dir, struct dentry *dentry) { /* XXX - this is all fucked up! */ - /* XXX - and it's been broken since linux has this new dentry interface: - * allows reading of files, but screws the whole dcache, even outside - * of the ufs partition, so that umount'ing won't suffice to fix it -- - * reboot needed - */ unsigned long int lfragno, fragno; struct buffer_head * bh; struct ufs_direct * d; + struct super_block * sb = dir->i_sb; const char *name = dentry->d_name.name; int len = dentry->d_name.len; - __u32 bytesex; + __u32 flags; struct inode *inode; /* XXX - isn't that already done by the upper layer? */ if (!dir || !S_ISDIR(dir->i_mode)) return -EBADF; - bytesex = dir->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; + flags = sb->u.ufs_sb.s_flags; - if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) + if (flags & UFS_DEBUG) printk("Passed name: %s\nPassed length: %d\n", name, len); - /* debugging hacks: * Touching /xyzzy in a filesystem toggles debugging messages. */ if ((len == 5) && !(memcmp(name, "xyzzy", len)) && (dir->i_ino == UFS_ROOTINO)) { - dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG; + sb->u.ufs_sb.s_flags ^= UFS_DEBUG; printk("UFS debugging %s\n", - (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ? + (sb->u.ufs_sb.s_flags & UFS_DEBUG) ? "on": "off"); goto not_found; /*return(-ENOENT);*/ } /* - * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c. + * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c */ if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) && (dir->i_ino == UFS_ROOTINO)) { - dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE; + sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE; printk("UFS inode debugging %s\n", - (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ? + (sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ? "on": "off"); goto not_found; /*return(-ENOENT);*/ } + /* + * Touching /xyzzy.n in a filesystem toggles debugging for ufs_namei.c + */ if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) && (dir->i_ino == UFS_ROOTINO)) { - dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI; + sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI; printk("UFS namei debugging %s\n", - (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ? + (sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ? "on": "off"); goto not_found; /*return(-ENOENT);*/ } + /* + * Touching /xyzzy.l in a filesystem toggles debugging for ufs_symlink.c + */ if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) && (dir->i_ino == UFS_ROOTINO)) { - dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS; + sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS; printk("UFS symlink debugging %s\n", - (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ? + (sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ? "on": "off"); goto not_found; /*return(-ENOENT);*/ } - /* Now for the real thing */ - if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) { + if (flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) { printk("ufs_lookup: called for ino %lu name %s\n", dir->i_ino, name); } - /* XXX - do I want i_blocks in 512-blocks or 1024-blocks? */ - for (lfragno = 0; lfragno < (dir->i_blocks)>>1; lfragno++) { + for (lfragno = 0; lfragno < dir->i_blocks; lfragno++) { fragno = ufs_bmap(dir, lfragno); + /* ufs_bmap() reads the block (frag) size in s_blocksize */ /* XXX - ufs_bmap() call needs error checking */ - /* XXX - s_blocksize is actually the UFS frag size */ - if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (flags & UFS_DEBUG) { printk("ufs_lookup: ino %lu lfragno %lu fragno %lu\n", dir->i_ino, lfragno, fragno); } @@ -129,7 +132,7 @@ goto not_found; /*return(-ENOENT);*/ } - bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize); + bh = bread(dir->i_dev, fragno, sb->s_blocksize); if (bh == NULL) { printk("ufs_lookup: bread failed: " "ino %lu, lfragno %lu", @@ -138,17 +141,17 @@ } d = (struct ufs_direct *)(bh->b_data); while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <= - dir->i_sb->s_blocksize) { + sb->s_blocksize) { /* XXX - skip block if d_reclen or d_namlen is 0 */ - if ((d->d_reclen == 0) || (d->d_namlen == 0)) { + if ((d->d_reclen == 0) || (NAMLEN(d) == 0)) { /* no need to SWAB16(): test against 0 */ - if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (flags & UFS_DEBUG) { printk("ufs_lookup: skipped space in directory, ino %lu\n", dir->i_ino); } break; } - if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (flags & UFS_DEBUG) { printk("lfragno 0x%lx " "direct d 0x%x " "d_ino %u " @@ -158,30 +161,31 @@ (unsigned int)((unsigned long)d), SWAB32(d->d_ino), SWAB16(d->d_reclen), - SWAB16(d->d_namlen),d->d_name); + NAMLEN(d),d->d_name); } - if ((SWAB16(d->d_namlen) == len) && + if ((NAMLEN(d) == len) && /* XXX - don't use strncmp() - see ext2fs */ - (ufs_match(len, name, d, bytesex))) { + (ufs_match(len, name, d, flags))) { /* We have a match */ /* XXX - I only superficially understand how things work, * so use at your own risk... -- Fare' */ - inode = iget(dir->i_sb, SWAB32(d->d_ino)); + inode = iget(sb, SWAB32(d->d_ino)); brelse(bh); if(!inode) { return -EACCES; } d_add(dentry,inode); return(0); } else { /* XXX - bounds checking */ - if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (flags & UFS_DEBUG) { printk("ufs_lookup: " "wanted (%s,%d) got (%s,%d)\n", name, len, - d->d_name, SWAB16(d->d_namlen)); + d->d_name, NAMLEN(d)); } } - d = (struct ufs_direct *)((char *)d + SWAB16(d->d_reclen)); + d = (struct ufs_direct *)((char *)d + + SWAB16(d->d_reclen)); } brelse(bh); } diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v2.1.86/linux/fs/ufs/ufs_super.c Fri Dec 5 07:20:44 1997 +++ linux/fs/ufs/ufs_super.c Thu Feb 12 16:27:15 1998 @@ -19,8 +19,19 @@ * * Clean swab support on 19970406 by * Francois-Rene Rideau + * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . + * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen . */ +#undef DEBUG_UFS_SUPER +/*#define DEBUG_UFS_SUPER 1*/ +/* Uncomment the line above when hacking ufs superblock code */ + #include #include @@ -42,7 +53,7 @@ NULL, /* XXX - ufs_write_inode() */ ufs_put_inode, NULL, /* XXX - ufs_delete_inode() */ - NULL, /* notify_change() */ + NULL, /* XXX - notify_change() */ ufs_put_super, NULL, /* XXX - ufs_write_super() */ ufs_statfs, @@ -89,23 +100,26 @@ kdevname(sb->s_dev), function, error_buf); } -#if 0 /* unused */ +#ifdef DEBUG_UFS_SUPER static void ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb) { + __u32 flags = sb->u.ufs_sb.s_flags; printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno); - printk("fs_size: 0x%8.8x\n", usb->fs_size); - printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg); - printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize); - printk("fs_frag: 0x%8.8x\n", usb->fs_frag); + printk("fs_size: 0x%8.8x\n", usb->fs_size); + printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg); + printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize); + printk("fs_fsize: 0x%8.8x\n", usb->fs_fsize); + printk("fs_frag: 0x%8.8x\n", usb->fs_frag); printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir); - printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb); - printk("fs_optim: 0x%8.8x\n", usb->fs_optim); - printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl); - printk("fs_state: 0x%8.8x\n", usb->fs_state); - printk("fs_magic: 0x%8.8x\n", usb->fs_magic); - printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt); + printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb); + printk("fs_optim: 0x%8.8x\n", usb->fs_optim); + printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl); + printk("fs_clean: 0x%8.8x\n", usb->fs_clean); + printk("fs_state: 0x%8.8x\n", UFS_STATE(usb)); + printk("fs_magic: 0x%8.8x\n", usb->fs_magic); + printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt); return; } @@ -116,7 +130,9 @@ { struct ufs_superblock * usb; /* normalized to local byteorder */ struct buffer_head * bh1, *bh2; - __u32 bytesex = 0; + __u32 flags = UFS_DEBUG_INITIAL; /* for sb->u.ufs_sb.s_flags */ + static int offsets[] = { 0, 96, 160 }; /* different superblock locations */ + int i; /* sb->s_dev and sb->s_flags are set by our caller * data is the mystery argument to sys_mount() @@ -127,102 +143,137 @@ MOD_INC_USE_COUNT; lock_super (sb); + set_blocksize (sb->s_dev, BLOCK_SIZE); /* XXX - make everything read only for testing */ sb->s_flags |= MS_RDONLY; - if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) || - !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE, - BLOCK_SIZE))) { - brelse(bh1); - printk ("ufs_read_super: unable to read superblock\n"); + for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) { + if (!(bh1 = bread(sb->s_dev, offsets[i] + UFS_SBLOCK/BLOCK_SIZE, + BLOCK_SIZE)) || + !(bh2 = bread(sb->s_dev, offsets[i] + + UFS_SBLOCK/BLOCK_SIZE + 1, BLOCK_SIZE))) { + brelse(bh1); + printk ("ufs_read_super: unable to read superblock\n"); + goto ufs_read_super_lose; + } + /* XXX - redo this so we can free it later... */ + usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL); + if (usb == NULL) { + brelse(bh1); + brelse(bh2); + printk ("ufs_read_super: get_free_page() failed\n"); + goto ufs_read_super_lose; + } + + memcpy((char *)usb, bh1->b_data, BLOCK_SIZE); + memcpy((char *)usb + BLOCK_SIZE, bh2->b_data, + sizeof(struct ufs_superblock) - BLOCK_SIZE); - goto ufs_read_super_lose; - } - /* XXX - redo this so we can free it later... */ - usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL); - if (usb == NULL) { brelse(bh1); brelse(bh2); - printk ("ufs_read_super: get_free_page() failed\n"); - goto ufs_read_super_lose; - } - - memcpy((char *)usb, bh1->b_data, BLOCK_SIZE); - memcpy((char *)usb + BLOCK_SIZE, bh2->b_data, - sizeof(struct ufs_superblock) - BLOCK_SIZE); - - brelse(bh1); - brelse(bh2); - - switch (le32_to_cpup(&usb->fs_magic)) { - case UFS_MAGIC: - bytesex = UFS_LITTLE_ENDIAN; - ufs_superblock_le_to_cpus(usb); - break; - case UFS_CIGAM: - bytesex = UFS_BIG_ENDIAN; - ufs_superblock_be_to_cpus(usb); - break; - /* usb is now normalized to local byteorder */ - default: - printk ("ufs_read_super: bad magic number 0x%8.8x " - "on dev %d/%d\n", usb->fs_magic, - MAJOR(sb->s_dev), MINOR(sb->s_dev)); - goto ufs_read_super_lose; + switch (le32_to_cpup(&usb->fs_magic)) { + case UFS_MAGIC: + flags |= UFS_LITTLE_ENDIAN; + ufs_superblock_le_to_cpus(usb); + goto found; + case UFS_CIGAM: + flags |= UFS_BIG_ENDIAN; + ufs_superblock_be_to_cpus(usb); + goto found; + /* usb is now normalized to local byteorder */ + default: + } } - + printk ("ufs_read_super: bad magic number 0x%8.8x " + "on dev %d/%d\n", usb->fs_magic, + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + goto ufs_read_super_lose; +found: +#ifdef DEBUG_UFS_SUPER + printk("ufs_read_super: superblock offset 0x%2.2x\n", offsets[i]); +#endif /* We found a UFS filesystem on this device. */ /* XXX - parse args */ - if (usb->fs_bsize != UFS_BSIZE) { - printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize, - UFS_BSIZE); + if ((usb->fs_bsize != 4096) && (usb->fs_bsize != 8192)) { + printk("ufs_read_super: invalid fs_bsize = %d\n", + usb->fs_bsize); goto ufs_read_super_lose; } - if (usb->fs_fsize != UFS_FSIZE) { - printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize, - UFS_FSIZE); + if ((usb->fs_fsize != 512) && (usb->fs_fsize != 1024)) { + printk("ufs_read_super: invalid fs_fsize = %d\n", + usb->fs_fsize); goto ufs_read_super_lose; } + if (usb->fs_fsize != BLOCK_SIZE) { + set_blocksize (sb->s_dev, usb->fs_fsize); + } + flags |= UFS_VANILLA; + /* XXX more consistency check */ #ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt); + printk("ufs_read_super: maxsymlinklen 0x%8.8x\n", + usb->fs_u.fs_44.fs_maxsymlinklen); #endif + if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) { + if (usb->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) { + flags |= UFS_44BSD; + } else { + flags |= UFS_OLD; /* 4.2BSD */ + } + } else if (offsets[i] > 0) { + flags |= UFS_NEXT; + } else { + flags |= UFS_SUN; + } - if (usb->fs_state == UFS_FSOK - usb->fs_time) { - switch(usb->fs_clean) { - case UFS_FSCLEAN: #ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: fs is clean\n"); + ufs_print_super_stuff(sb, usb); +#endif + if ( ((flags&UFS_ST_MASK)==UFS_ST_44BSD) + || ((flags&UFS_ST_MASK)==UFS_ST_OLD) + || ((flags&UFS_ST_MASK)==UFS_ST_NEXT) + || ( ((flags&UFS_ST_MASK)==UFS_ST_SUN) + && UFS_STATE(usb) == UFS_FSOK - usb->fs_time)) { + switch(usb->fs_clean) { + case UFS_FSACTIVE: /* 0x00 */ + printk("ufs_read_super: fs is active\n"); + sb->s_flags |= MS_RDONLY; + break; + case UFS_FSCLEAN: /* 0x01 */ +#ifdef DEBUG_UFS_SUPER + printk("ufs_read_super: fs is clean\n"); +#endif + break; + case UFS_FSSTABLE: /* 0x02 */ +#ifdef DEBUG_UFS_SUPER + printk("ufs_read_super: fs is stable\n"); #endif - break; - case UFS_FSSTABLE: + break; + case UFS_FSOSF1: /* 0x03 */ + /* XXX is this correct for DEC OSF/1? */ #ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: fs is stable\n"); + printk("ufs_read_super: fs is clean and stable (OSF/1)\n"); #endif - break; - case UFS_FSACTIVE: - printk("ufs_read_super: fs is active\n"); - sb->s_flags |= MS_RDONLY; - break; - case UFS_FSBAD: - printk("ufs_read_super: fs is bad\n"); - sb->s_flags |= MS_RDONLY; - break; - default: - printk("ufs_read_super: can't grok fs_clean 0x%x\n", - usb->fs_clean); - sb->s_flags |= MS_RDONLY; - break; - } + break; + case UFS_FSBAD: /* 0xFF */ + printk("ufs_read_super: fs is bad\n"); + sb->s_flags |= MS_RDONLY; + break; + default: + printk("ufs_read_super: can't grok fs_clean 0x%x\n", + usb->fs_clean); + sb->s_flags |= MS_RDONLY; + break; + } } else { - printk("ufs_read_super: fs needs fsck\n"); - sb->s_flags |= MS_RDONLY; - /* XXX - make it read only or barf if it's not (/, /usr) */ + printk("ufs_read_super: fs needs fsck\n"); + sb->s_flags |= MS_RDONLY; + /* XXX - make it read only or barf if it's not (/, /usr) */ } /* XXX - sanity check sb fields */ @@ -238,7 +289,7 @@ /* sb->s_wait */ /* XXX - sb->u.ufs_sb */ sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */ - sb->u.ufs_sb.s_flags = bytesex | UFS_DEBUG_INITIAL ; + sb->u.ufs_sb.s_flags = flags ; sb->u.ufs_sb.s_ncg = usb->fs_ncg; sb->u.ufs_sb.s_ipg = usb->fs_ipg; sb->u.ufs_sb.s_fpg = usb->fs_fpg; @@ -257,6 +308,7 @@ sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask) >> usb->fs_fshift); sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */ + sb->u.ufs_sb.s_blockbase = offsets[i]; sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL); #ifdef DEBUG_UFS_SUPER @@ -271,6 +323,7 @@ ufs_read_super_lose: /* XXX - clean up */ + set_blocksize (sb->s_dev, BLOCK_SIZE); sb->s_dev = 0; unlock_super (sb); MOD_DEC_USE_COUNT; @@ -285,6 +338,7 @@ lock_super (sb); /* XXX - sync fs data, set state to ok, and flush buffers */ + set_blocksize (sb->s_dev, BLOCK_SIZE); sb->s_dev = 0; /* XXX - free allocated kernel memory */ diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_swab.c linux/fs/ufs/ufs_swab.c --- v2.1.86/linux/fs/ufs/ufs_swab.c Fri Jan 30 11:28:09 1998 +++ linux/fs/ufs/ufs_swab.c Thu Feb 12 16:27:15 1998 @@ -36,6 +36,10 @@ * 2) instead of byteswapping, use [bl]e_to_cpu: * it might be that we run on a VAX! * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . + * * HOWTO continue adding swab support: * basically, anywhere metadata is bread() (i.e. mapped to block device), * data should either be SWAB()ed on the fly, @@ -106,33 +110,69 @@ /* * Here are the whole-structure swabping routines... + * They were fun to design, but I don't understand why we + * need a copy of the superblock, anyway. -- Fare' */ extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb) { #ifndef __BIG_ENDIAN + __u16 sb_type = 1; /* SUN type superblock */ + + if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) + sb_type = 0; /* 4.4BSD (FreeBSD) type superblock */ + be32_to_cpus__between(*usb,fs_link,fs_fmod); /* XXX - I dunno what to do w/ fs_csp, * but it is unused by the current code, so that's ok for now. */ be32_to_cpus(&usb->fs_cpc); - be16_to_cpus__between(*usb,fs_opostbl,fs_sparecon); - be32_to_cpus__between(*usb,fs_sparecon,fs_qbmask); - be64_to_cpus((__u64 *) &usb->fs_qbmask); - be64_to_cpus((__u64 *) &usb->fs_qfmask); + if (sb_type) { + be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon); + be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask); + /* Might fail on strictly aligning 64-bit big-endian + * architectures. Ouch! + */ + be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask); + be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask); + } else { + be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon); + be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize); + be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize); + be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask); + be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask); + be32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state); + } be32_to_cpus__between(*usb,fs_postblformat,fs_magic); #endif } extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb) { #ifndef __LITTLE_ENDIAN + __u16 sb_type = 1; /* SUN type superblock */ + + if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) + sb_type = 0; /* 4.4BSD (FreeBSD) type superblock */ + le32_to_cpus__between(*usb,fs_link,fs_fmod); /* XXX - I dunno what to do w/ fs_csp, * but it is unused by the current code, so that's ok for now. */ le32_to_cpus(&usb->fs_cpc); - le16_to_cpus__between(*usb,fs_opostbl,fs_sparecon); - le32_to_cpus__between(*usb,fs_sparecon,fs_qbmask); - le64_to_cpus(&usb->fs_qbmask); - le64_to_cpus(&usb->fs_qfmask); + if (sb_type) { + le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon); + le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask); + /* Might fail on strictly aligning 64-bit big-endian + * architectures. Ouch! + */ + le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask); + le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask); + } else { + le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon); + le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize); + le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize); + le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask); + le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask); + le32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state); + } le32_to_cpus__between(*usb,fs_postblformat,fs_magic); #endif } diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_swab.h linux/fs/ufs/ufs_swab.h --- v2.1.86/linux/fs/ufs/ufs_swab.h Sun Nov 9 14:51:04 1997 +++ linux/fs/ufs/ufs_swab.h Thu Feb 12 16:27:15 1998 @@ -18,42 +18,104 @@ * to support them. * (2) for a read/write ufs driver, we should distinguish * between byteswapping for read or write accesses! + * naming should then be UFS16_TO_CPU and suches. + * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . */ #include #include /* - * These are only valid inside ufs routines, - * after bytesex has been initialized to sb->u.ufs_sb.s_flags&UFS_BYTESEX + * These are only valid inside ufs routines, after a variable named flags + * has been made visible in current scope and properly initialized: + __u32 flags = sb->u.ufs_sb.s_flags ; */ -#define SWAB16(x) ufs_swab16(bytesex,x) -#define SWAB32(x) ufs_swab32(bytesex,x) -#define SWAB64(x) ufs_swab64(bytesex,x) +#define SWAB16(x) ufs_swab16(flags,x) +#define SWAB32(x) ufs_swab32(flags,x) +#define SWAB64(x) ufs_swab64(flags,x) -extern __inline__ __const__ __u16 ufs_swab16(__u32 bytesex, __u16 x) { - if (bytesex == UFS_LITTLE_ENDIAN) { +extern __inline__ __const__ __u16 ufs_swab16(__u32 flags, __u16 x) { + if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) { return le16_to_cpu(x); } else { return be16_to_cpu(x); } } -extern __inline__ __const__ __u32 ufs_swab32(__u32 bytesex, __u32 x) { - if (bytesex == UFS_LITTLE_ENDIAN) { +extern __inline__ __const__ __u32 ufs_swab32(__u32 flags, __u32 x) { + if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) { return le32_to_cpu(x); } else { return be32_to_cpu(x); } } -extern __inline__ __const__ __u64 ufs_swab64(__u32 bytesex, __u64 x) { - if (bytesex == UFS_LITTLE_ENDIAN) { +extern __inline__ __const__ __u64 ufs_swab64(__u32 flags, __u64 x) { + if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) { return le64_to_cpu(x); } else { return be64_to_cpu(x); } } + +/* + * These are for in-core superblock normalization. + * It might or not be a bad idea once we go to a read/write driver, + * as all critical info should be copied to the sb info structure anyway. + * So better replace them with a static inline function + * ufs_superblock_to_sb_info() in ufs_super.c + */ extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb); extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb); + + +/* + * These also implicitly depend on variable flags... + * NAMLEN(foo) is already normalized to local format, so don't SWAB16() it! + */ + +#define NAMLEN(direct) ufs_namlen(flags,direct) +extern __inline__ __u16 ufs_namlen(__u32 flags, struct ufs_direct * direct) { + if ( (flags&UFS_DE_MASK) == UFS_DE_OLD) { + return SWAB16(direct->d_u.d_namlen); + } else /* UFS_DE_44BSD */ { + return direct->d_u.d_44.d_namlen; + } +} + +/* Here is how the uid is computed: + if the file system is 4.2BSD, get it from oldids. + if it has sun extension and oldids is USEEFT, get it from ui_sun. + if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd). + depends on implicit variable flags being initialized from + __u32 flags = sb->u.ufs_sb.s_flags; +*/ +#define UFS_UID(ino) ufs_uid(flags,ino) +#define UFS_GID(ino) ufs_gid(flags,ino) + +extern __inline__ __u32 ufs_uid(__u32 flags,struct ufs_inode * ino) { + switch(flags&UFS_UID_MASK) { + case UFS_UID_EFT: + return SWAB32(ino->ui_u3.ui_sun.ui_uid) ; + case UFS_UID_44BSD: + return SWAB32(ino->ui_u3.ui_44.ui_uid) ; + case UFS_UID_OLD: + default: + return SWAB16(ino->ui_u1.oldids.suid) ; + } +} +extern __inline__ __u32 ufs_gid(__u32 flags,struct ufs_inode * ino) { + switch(flags&UFS_UID_MASK) { + case UFS_UID_EFT: + return SWAB32(ino->ui_u3.ui_sun.ui_gid) ; + case UFS_UID_44BSD: + return SWAB32(ino->ui_u3.ui_44.ui_gid) ; + case UFS_UID_OLD: + default: + return SWAB16(ino->ui_u1.oldids.sgid) ; + } +} #endif /* _UFS_SWAB_H */ diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c --- v2.1.86/linux/fs/ufs/ufs_symlink.c Sun Jan 4 00:53:41 1998 +++ linux/fs/ufs/ufs_symlink.c Thu Feb 12 16:27:15 1998 @@ -8,6 +8,9 @@ * * Ported to 2.1.62 by Francois-Rene Rideau 19971109 * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . */ #include @@ -22,13 +25,14 @@ ufs_readlink(struct dentry * dentry, char * buffer, int buflen) { struct inode * inode = dentry->d_inode; + struct super_block * sb = inode->i_sb; unsigned long int block; struct buffer_head * bh = NULL; char * link; int i; char c; - if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { + if (sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { printk("ufs_readlink: called on ino %lu dev %u/%u\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } @@ -37,16 +41,16 @@ return -EINVAL; } - if (buflen > inode->i_sb->s_blocksize - 1) - buflen = inode->i_sb->s_blocksize - 1; + if (buflen > sb->s_blocksize - 1) + buflen = sb->s_blocksize - 1; if (inode->i_blocks) { /* XXX - error checking */ block = ufs_bmap(inode, 0); - if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) { + if (sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) { printk("ufs_readlink: bmap got %lu for ino %lu\n", block, inode->i_ino); } - bh = bread(inode->i_dev, block, BLOCK_SIZE); + bh = bread(inode->i_dev, block, sb->s_blocksize); if (!bh) { printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n", inode->i_ino, MAJOR(inode->i_dev), @@ -55,9 +59,8 @@ } link = bh->b_data; /* no need to bswap */ - } - else { - link = (char *)&(inode->u.ufs_i.i_data[0]); + } else /* fast symlink */ { + link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]); } i = 0; while (i < buflen && (c = link[i])) { @@ -88,7 +91,7 @@ /* read the link from disk */ /* XXX - error checking */ block = ufs_bmap(inode, 0); - bh = bread(inode->i_dev, block, BLOCK_SIZE); + bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize); if (bh == NULL) { printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n", inode->i_ino, MAJOR(inode->i_dev), @@ -97,9 +100,8 @@ return ERR_PTR(-EIO); } link = bh->b_data; - } else { - /* fast symlink */ - link = (char *)&(inode->u.ufs_i.i_data[0]); + } else /* fast symlink */ { + link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]); } base = lookup_dentry(link, base, 1); brelse (bh); diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile --- v2.1.86/linux/fs/umsdos/Makefile Tue Aug 15 05:07:02 1995 +++ linux/fs/umsdos/Makefile Thu Feb 12 13:36:57 1998 @@ -6,10 +6,13 @@ # unless it's something special (ie not a .c file). # # Note 2! The CFLAGS definitions are now in the main makefile... - O_TARGET := umsdos.o -O_OBJS := dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o \ - rdir.o symlink.o #check.o + +O_OBJS := dir.o file.o inode.o ioctl.o mangle.o namei.o \ + rdir.o symlink.o emd.o + +#check.o + M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt --- v2.1.86/linux/fs/umsdos/README-WIP.txt Wed Dec 31 16:00:00 1969 +++ linux/fs/umsdos/README-WIP.txt Thu Feb 12 13:36:57 1998 @@ -0,0 +1,89 @@ +Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing +(started by Peter T. Waltenberg ) + +Current status (980211) - UMSDOS dentry-WIP-Beta 0.82: + +(1) pure MSDOS (no --linux-.--- EMD file): + +- readdir - works +- lookup - works +- read file - works + +- creat file - works +- write file - works +- mkdir - works +- rmdir - questionable. probable problem on non-empty dirs. + +Notes: possible very minor problems with dentry/inode/... kernel structures (very rare) + + +(2) umsdos (with --linux-.--- EMD file): + +- readdir - works. problems with symlink/hardlink resolving. see below. +- lookup - works. problems with symlink/hardlink resolving. see below. +- permissions/owners stuff - works +- long file names - works +- read file - works +- switching MSDOS/UMSDOS - untested +- switching UMSDOS/MSDOS - untested +- pseudo root things - commented out mostly currently. To be fixed when + dentries stuff is straightened out. +- resolve symlink - seems to work (ls -l shows both symlink and filename it + points to, but dereferencing does not work. see below) +- dereference symlink - for some strange reason does not work. Is + follow_symlink now obligatory (in contrary what is said in + linux/Documentation/fs/vfs.txt ?) - working on it +- hard links - totally defunct currently. +- special files (block/char device, fifos, sockets...) - seems to work ok. +- other ioctls - mostly untested + +- create symlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- create hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- creat file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- write file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- mkdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- rmdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- umssyncing - WARNING: NONE OF WRITE OPERATIONS FIXED YET! + +Notes: heavy dentry kernel structures trashing. Probably some other kernel +structures compromised. Have SysRq support compiled in, and use +Sync/Emergency-remount-RO. And don't try mounting read/write yet - and then +you should have no big problems... + +Notes2: kernel structures trashing seems to be _MUCH_ lower if no +symlinks/hardlink present. (hardlinks seem to be biggest problem) + +------------------------------------------------------------------------------ + +Some general notes: + +There is great amount of kernel log messages. Use SysRq log-level 5 to turn +most of them off, or 4 to turn all but really fatal ones off. Probably good +idea to kill klogd/syslogd so it will only go to console. + +It should work enough to test it, but probably not enough to give you second +chance to umount/rmmod module, recompile it, and reinsert it again. This is +first on my list of things to get fixed, as it would greatly improve speed +of compile/test/reboot/set_environment/recompile cycle by removing +'reboot/set_environment' component. + +But I need some help from someone knowing about dentries/inodes use more +than I. If you can help, please contact me... + +I'm unfortunatelly totally out of time to read linux-kernel, but I do check +for any messages having UMSDOS in subject, and read them. I should reply to +any direct Email in few days. If I don't - probably I never got your +message. You can try mnalis@open.hr or mnalis@voyager.hr; however +mnalis@jagor.srce.hr is preferable one. + +------------------------------------------------------------------------------ + +some of my notes for myself: + +- hardlinks/symlinks. test with files in not_the_same_dir +- also test not_the_same_dir for other file operations like rename etc. +- iput: device 00:00 inode 318 still has aliases! problem. Check in iput() + for device 0,0. Probably null pointer passed arount when it shouldn't be ? +- dput/iput problem... +- what about .dotfiles ? working ? multiple dots ? etc.... + diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.1.86/linux/fs/umsdos/dir.c Mon Jun 16 16:35:59 1997 +++ linux/fs/umsdos/dir.c Thu Feb 12 13:36:57 1998 @@ -24,11 +24,58 @@ #define UMSDOS_SPECIAL_DIRFPOS 3 extern struct inode *pseudo_root; + + +/* P.T.Waltenberg + I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS + uses. It's easier to do once than hack all the other instances. Probably safer as well +*/ +int compat_UMSDOS_lookup(struct inode *dir,const char *name,int len, struct inode **inode) +{ + int rv; + struct dentry *dentry; + + dentry = creat_dentry (name, len, NULL); + rv = UMSDOS_lookup(dir,dentry); + + if (inode) *inode = dentry->d_inode; + return rv; +} + + +int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct inode **inode) +{ + int rv; + struct dentry *dentry; + + dentry = creat_dentry (name, len, NULL); + rv = umsdos_real_lookup(dir,dentry); + if (inode) *inode = dentry->d_inode; + + return rv; +} + + +int compat_msdos_create(struct inode *dir,const char *name,int len, int mode, struct inode **inode) +{ + int rv; + struct dentry *dentry; + + dentry = creat_dentry (name, len, NULL); + rv = msdos_create(dir,dentry,mode); + if(inode != NULL) *inode = dentry->d_inode; + + return rv; +} + + /* So grep * doesn't complain in the presence of directories. */ -long UMSDOS_dir_read(struct inode *inode,struct file *filp, - char *buf, unsigned long count) +int UMSDOS_dir_read(struct file *filp, + char *buff, + size_t size, + loff_t * count) { return -EISDIR; } @@ -43,554 +90,585 @@ /* Record a single entry the first call. Return -EINVAL the next one. + NOTE: filldir DOES NOT use a dentry */ static int umsdos_dir_once( void * buf, - const char * name, - int name_len, + const char *name, + int len, off_t offset, ino_t ino) { - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; - if (d->count == 0){ - #if 0 - char zname[100]; - memcpy (zname,name,name_len); - zname[name_len] = '\0'; - Printk (("dir_once :%s: offset %Ld\n",zname,offset)); - #endif - ret = d->filldir (d->dirbuf,name,name_len,offset,ino); - d->stop = ret < 0; - d->count = 1; - } - return ret; + int ret = -EINVAL; + struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; + if (d->count == 0){ +#if 0 + char zname[100]; + memcpy (zname,dentry->d_name,dentry->d_len); + zname[name_len] = '\0'; + Printk ((KERN_DEBUG "dir_once :%s: offset %Ld\n",zname,offset)); +#endif + ret = d->filldir (d->dirbuf,name,len,offset,ino); + d->stop = ret < 0; + d->count = 1; + } + return ret; } /* - Read count directory entries from directory filp - Return a negative value from linux/errno.h. - Return > 0 if success (The amount of byte written by filldir). - - This function is used by the normal readdir VFS entry point and by - some function who try to find out info on a file from a pure MSDOS - inode. See umsdos_locate_ancestor() below. + Read count directory entries from directory filp + Return a negative value from linux/errno.h. + Return > 0 if success (The amount of byte written by filldir). + + This function is used by the normal readdir VFS entry point and by + some function who try to find out info on a file from a pure MSDOS + inode. See umsdos_locate_ancestor() below. */ static int umsdos_readdir_x( - struct inode *dir, /* Point to a description of the super block */ - struct file *filp, /* Point to a directory which is read */ - void *dirbuf, /* Will hold count directory entry */ - /* but filled by the filldir function */ - int internal_read, /* Called for internal purpose */ - struct umsdos_dirent *u_entry, /* Optional umsdos entry */ - int follow_hlink, - filldir_t filldir) -{ - int ret = 0; - - umsdos_startlookup(dir); - if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS - && dir == pseudo_root - && !internal_read){ - /* - We don't need to simulate this pseudo directory - when umsdos_readdir_x is called for internal operation - of umsdos. This is why dirent_in_fs is tested - */ - /* #Specification: pseudo root / directory /DOS - When umsdos operates in pseudo root mode (C:\linux is the - linux root), it simulate a directory /DOS which points to - the real root of the file system. - */ - if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS - ,dir->i_sb->s_mounted->i_ino) == 0){ - filp->f_pos++; - } - }else if (filp->f_pos < 2 - || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){ - /* #Specification: readdir / . and .. - The msdos filesystem manage the . and .. entry properly - so the EMD file won't hold any info about it. - - In readdir, we assume that for the root directory - the read position will be 0 for ".", 1 for "..". For - a non root directory, the read position will be 0 for "." - and 32 for "..". - */ - /* - This is a trick used by the msdos file system (fs/msdos/dir.c) - to manage . and .. for the root directory of a file system. - Since there is no such entry in the root, fs/msdos/dir.c - use the following: - - if f_pos == 0, return ".". - if f_pos == 1, return "..". - - So let msdos handle it - - Since umsdos entries are much larger, we share the same f_pos. - if f_pos is 0 or 1 or 32, we are clearly looking at . and - .. - - As soon as we get f_pos == 2 or f_pos == 64, then back to - 0, but this time we are reading the EMD file. - - Well, not so true. The problem, is that UMSDOS_REC_SIZE is - also 64, so as soon as we read the first record in the - EMD, we are back at offset 64. So we set the offset - to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the - .. entry from msdos. - - Now (linux 1.3), umsdos_readdir can read more than one - entry even if we limit (umsdos_dir_once) to only one: - It skips over hidden file. So we switch to - UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully - the .. entry. - */ - int last_f_pos = filp->f_pos; - struct UMSDOS_DIR_ONCE bufk; - bufk.dirbuf = dirbuf; - bufk.filldir = filldir; - bufk.count = 0; - ret = fat_readdir(dir,filp,&bufk,umsdos_dir_once); - if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; - if (u_entry != NULL) u_entry->flags = 0; - }else{ - struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0); - if (emd_dir != NULL){ - off_t start_fpos = filp->f_pos; - if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0; - PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size)); - ret = 0; - while (filp->f_pos < emd_dir->i_size){ - struct umsdos_dirent entry; - off_t cur_f_pos = filp->f_pos; - if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){ - ret = -EIO; - break; - }else if (entry.name_len != 0){ - /* #Specification: umsdos / readdir - umsdos_readdir() should fill a struct dirent with - an inode number. The cheap way to get it is to - do a lookup in the MSDOS directory for each - entry processed by the readdir() function. - This is not very efficient, but very simple. The - other way around is to maintain a copy of the inode - number in the EMD file. This is a problem because - this has to be maintained in sync using tricks. - Remember that MSDOS (the OS) does not update the - modification time (mtime) of a directory. There is - no easy way to tell that a directory was modified - during a DOS session and synchronise the EMD file. - - Suggestion welcome. - - So the easy way is used! - */ - struct umsdos_info info; - struct inode *inode; - int lret; - umsdos_parse (entry.name,entry.name_len,&info); - info.f_pos = cur_f_pos; - umsdos_manglename (&info); - lret = umsdos_real_lookup (dir,info.fake.fname - ,info.fake.len,&inode); - PRINTK (("Cherche inode de %s lret %d flags %d\n" - ,info.fake.fname,lret,entry.flags)); - if (lret == 0 - && (entry.flags & UMSDOS_HLINK) - && follow_hlink){ - struct inode *rinode; - lret = umsdos_hlink2inode (inode,&rinode); - inode = rinode; - } - if (lret == 0){ - /* #Specification: pseudo root / reading real root - The pseudo root (/linux) is logically - erased from the real root. This mean that - ls /DOS, won't show "linux". This avoids - infinite recursion /DOS/linux/DOS/linux while - walking the file system. - */ - if (inode != pseudo_root - && (internal_read - || !(entry.flags & UMSDOS_HIDDEN))){ - if (filldir (dirbuf - ,entry.name,entry.name_len - ,cur_f_pos, inode->i_ino) < 0){ - filp->f_pos = cur_f_pos; - } - PRINTK (("Trouve ino %ld ",inode->i_ino)); - if (u_entry != NULL) *u_entry = entry; - iput (inode); - break; - } - iput (inode); - }else{ - /* #Specification: umsdos / readdir / not in MSDOS - During a readdir operation, if the file is not - in the MSDOS directory anymore, the entry is - removed from the EMD file silently. - */ - ret = umsdos_writeentry (dir,emd_dir,&info,1); - if (ret != 0){ - break; - } - } - } - } - /* - If the fillbuf has failed, f_pos is back to 0. - To avoid getting back into the . and .. state - (see comments at the beginning), we put back - the special offset. - */ - if (filp->f_pos == 0) filp->f_pos = start_fpos; - iput(emd_dir); - } + struct inode *dir, /* Point to a description of the super block */ + struct file *filp, /* Point to a directory which is read */ + void *dirbuf, /* Will hold count directory entry */ + /* but filled by the filldir function */ + int internal_read, /* Called for internal purpose */ + struct umsdos_dirent *u_entry, /* Optional umsdos entry */ + int follow_hlink, + filldir_t filldir) +{ + int ret = 0; + struct inode *root_inode; + + root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO); + umsdos_startlookup(dir); + if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS + && pseudo_root + && dir == pseudo_root + && !internal_read){ + + Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n")); + /* + We don't need to simulate this pseudo directory + when umsdos_readdir_x is called for internal operation + of umsdos. This is why dirent_in_fs is tested + */ + /* #Specification: pseudo root / directory /DOS + When umsdos operates in pseudo root mode (C:\linux is the + linux root), it simulate a directory /DOS which points to + the real root of the file system. + */ + if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS + ,UMSDOS_ROOT_INO) == 0){ + filp->f_pos++; + } + }else if (filp->f_pos < 2 + || (dir != root_inode && filp->f_pos == 32)){ + /* #Specification: readdir / . and .. + The msdos filesystem manage the . and .. entry properly + so the EMD file won't hold any info about it. + + In readdir, we assume that for the root directory + the read position will be 0 for ".", 1 for "..". For + a non root directory, the read position will be 0 for "." + and 32 for "..". + */ + /* + This is a trick used by the msdos file system (fs/msdos/dir.c) + to manage . and .. for the root directory of a file system. + Since there is no such entry in the root, fs/msdos/dir.c + use the following: + + if f_pos == 0, return ".". + if f_pos == 1, return "..". + + So let msdos handle it + + Since umsdos entries are much larger, we share the same f_pos. + if f_pos is 0 or 1 or 32, we are clearly looking at . and + .. + + As soon as we get f_pos == 2 or f_pos == 64, then back to + 0, but this time we are reading the EMD file. + + Well, not so true. The problem, is that UMSDOS_REC_SIZE is + also 64, so as soon as we read the first record in the + EMD, we are back at offset 64. So we set the offset + to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the + .. entry from msdos. + + Now (linux 1.3), umsdos_readdir can read more than one + entry even if we limit (umsdos_dir_once) to only one: + It skips over hidden file. So we switch to + UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully + the .. entry. + */ + int last_f_pos = filp->f_pos; + struct UMSDOS_DIR_ONCE bufk; + + Printk (("umsdos_readdir_x: . or .. /mn/?\n")); + + bufk.dirbuf = dirbuf; + bufk.filldir = filldir; + bufk.count = 0; + + ret = fat_readdir(filp,&bufk,umsdos_dir_once); + if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; + if (u_entry != NULL) u_entry->flags = 0; + }else{ + struct inode *emd_dir; + Printk (("umsdos_readdir_x: normal file /mn/?\n")); + emd_dir = umsdos_emd_dir_lookup(dir,0); + if (emd_dir != NULL){ + off_t start_fpos = filp->f_pos; + Printk (("umsdos_readdir_x: emd_dir->i_ino=%d\n",emd_dir->i_ino)); + if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0; + Printk (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size)); + ret = 0; + while (filp->f_pos < emd_dir->i_size){ + struct umsdos_dirent entry; + off_t cur_f_pos = filp->f_pos; + if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){ + ret = -EIO; + break; + }else if (entry.name_len != 0){ + /* #Specification: umsdos / readdir + umsdos_readdir() should fill a struct dirent with + an inode number. The cheap way to get it is to + do a lookup in the MSDOS directory for each + entry processed by the readdir() function. + This is not very efficient, but very simple. The + other way around is to maintain a copy of the inode + number in the EMD file. This is a problem because + this has to be maintained in sync using tricks. + Remember that MSDOS (the OS) does not update the + modification time (mtime) of a directory. There is + no easy way to tell that a directory was modified + during a DOS session and synchronise the EMD file. + + Suggestion welcome. + + So the easy way is used! + */ + struct umsdos_info info; + struct inode *inode; + + int lret; + umsdos_parse (entry.name,entry.name_len,&info); + info.f_pos = cur_f_pos; + umsdos_manglename (&info); + /* FIXME, fake a dentry --> /mn/ fixed ? */ + lret = compat_umsdos_real_lookup (dir,info.fake.fname, + info.fake.len,&inode); + Printk (("Cherche inode de %s lret %d flags %d\n" + ,info.fake.fname,lret,entry.flags)); + if (lret == 0 + && (entry.flags & UMSDOS_HLINK) + && follow_hlink){ + struct inode *rinode; + lret = umsdos_hlink2inode (inode,&rinode); + inode = rinode; + } + if (lret == 0){ + /* #Specification: pseudo root / reading real root + The pseudo root (/linux) is logically + erased from the real root. This mean that + ls /DOS, won't show "linux". This avoids + infinite recursion /DOS/linux/DOS/linux while + walking the file system. + */ + if (inode != pseudo_root + && (internal_read + || !(entry.flags & UMSDOS_HIDDEN))){ + if (filldir (dirbuf, + entry.name, + entry.name_len, + cur_f_pos, + inode->i_ino) < 0){ + filp->f_pos = cur_f_pos; + } + Printk (("Trouve ino %ld ",inode->i_ino)); + if (u_entry != NULL) *u_entry = entry; + iput (inode); + break; + } + iput (inode); + }else{ + /* #Specification: umsdos / readdir / not in MSDOS + During a readdir operation, if the file is not + in the MSDOS directory anymore, the entry is + removed from the EMD file silently. + */ + Printk (("'Silently' removing EMD for file\n")); + ret = umsdos_writeentry (dir,emd_dir,&info,1); + if (ret != 0){ + break; + } + } } - umsdos_endlookup(dir); - PRINTK (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret)); - return ret; + } + /* + If the fillbuf has failed, f_pos is back to 0. + To avoid getting back into the . and .. state + (see comments at the beginning), we put back + the special offset. + */ + if (filp->f_pos == 0) filp->f_pos = start_fpos; + iput(emd_dir); + } + } + umsdos_endlookup(dir); + Printk (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret)); + return ret; } + + /* - Read count directory entries from directory filp - Return a negative value from linux/errno.h. - Return 0 or positive if successful + Read count directory entries from directory filp + Return a negative value from linux/errno.h. + Return 0 or positive if successful */ static int UMSDOS_readdir( - struct inode *dir, /* Point to a description of the super block */ - struct file *filp, /* Point to a directory which is read */ - void *dirbuf, /* Will hold directory entries */ - filldir_t filldir) -{ - int ret = 0; - int count = 0; - struct UMSDOS_DIR_ONCE bufk; - bufk.dirbuf = dirbuf; - bufk.filldir = filldir; - bufk.stop = 0; - PRINTK (("UMSDOS_readdir in\n")); - while (ret == 0 && bufk.stop == 0){ - struct umsdos_dirent entry; - bufk.count = 0; - ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once); - if (bufk.count == 0) break; - count += bufk.count; - } - PRINTK (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count - ,filp->f_pos)); - return count?:ret; + struct file *filp, /* Point to a directory which is read */ + void *dirbuf, /* Will hold directory entries */ + filldir_t filldir) +{ + struct inode *dir = filp->f_dentry->d_inode; + int ret = 0; + int count = 0; + struct UMSDOS_DIR_ONCE bufk; + bufk.dirbuf = dirbuf; + bufk.filldir = filldir; + bufk.stop = 0; + + Printk (("UMSDOS_readdir in\n")); + while (ret == 0 && bufk.stop == 0){ + struct umsdos_dirent entry; + bufk.count = 0; + Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%d)\n",dir,filp,&bufk,0,&entry,1,umsdos_dir_once)); + ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once); + if (bufk.count == 0) break; + count += bufk.count; + } + Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count + ,filp->f_pos)); + return count?:ret; } + /* - Complete the inode content with info from the EMD file + Complete the inode content with info from the EMD file */ void umsdos_lookup_patch ( - struct inode *dir, - struct inode *inode, - struct umsdos_dirent *entry, - off_t emd_pos) -{ - /* - This function modify the state of a dir inode. It decides - if the dir is a umsdos dir or a dos dir. This is done - deeper in umsdos_patch_inode() called at the end of this function. - - umsdos_patch_inode() may block because it is doing disk access. - At the same time, another process may get here to initialise - the same dir inode. There is 3 cases. - - 1-The inode is already initialised. We do nothing. - 2-The inode is not initialised. We lock access and do it. - 3-Like 2 but another process has lock the inode, so we try - to lock it and right after check if initialisation is still - needed. - - - Thanks to the mem option of the kernel command line, it was - possible to consistently reproduce this problem by limiting - my mem to 4 meg and running X. - */ - /* - Do this only if the inode is freshly read, because we will lose - the current (updated) content. - */ - /* - A lookup of a mount point directory yield the inode into - the other fs, so we don't care about initialising it. iget() - does this automatically. - */ - if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){ - if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode); - if (!umsdos_isinit(inode)){ - /* #Specification: umsdos / lookup / inode info - After successfully reading an inode from the MSDOS - filesystem, we use the EMD file to complete it. - We update the following field. - - uid, gid, atime, ctime, mtime, mode. - - We rely on MSDOS for mtime. If the file - was modified during an MSDOS session, at least - mtime will be meaningful. We do this only for regular - file. - - We don't rely on MSDOS for mtime for directory because - the MSDOS directory date is creation time (strange - MSDOS behavior) which fit nowhere in the three UNIX - time stamp. - */ - if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime; - inode->i_mode = entry->mode; - inode->i_rdev = to_kdev_t(entry->rdev); - inode->i_atime = entry->atime; - inode->i_ctime = entry->ctime; - inode->i_mtime = entry->mtime; - inode->i_uid = entry->uid; - inode->i_gid = entry->gid; - /* #Specification: umsdos / conversion mode - The msdos fs can do some inline conversion - of the data of a file. It can translate - silently from MsDOS text file format to Unix - one (crlf -> lf) while reading, and the reverse - while writing. This is activated using the mount - option conv=.... - - This is not useful for Linux file in promoted - directory. It can even be harmful. For this - reason, the binary (no conversion) mode is - always activated. - */ - /* #Specification: umsdos / conversion mode / todo - A flag could be added to file and directories - forcing an automatic conversion mode (as - done with the msdos fs). - - This flag could be setup on a directory basis - (instead of file) and all file in it would - logically inherited. If the conversion mode - is active (conv=) then the i_binary flag would - be left untouched in those directories. - - It was proposed that the sticky bit was used - to set this. The problem is that new file would - be written incorrectly. The other problem is that - the sticky bit has a meaning for directories. So - another bit should be used (there is some space - in the EMD file for it) and a special utilities - would be used to assign the flag to a directory). - I don't think it is useful to assign this flag - on a single file. - */ - - MSDOS_I(inode)->i_binary = 1; - /* #Specification: umsdos / i_nlink - The nlink field of an inode is maintain by the MSDOS file system - for directory and by UMSDOS for other file. The logic is that - MSDOS is already figuring out what to do for directories and - does nothing for other files. For MSDOS, there are no hard link - so all file carry nlink==1. UMSDOS use some info in the - EMD file to plug the correct value. - */ - if (!S_ISDIR(entry->mode)){ - if (entry->nlink > 0){ - inode->i_nlink = entry->nlink; - }else{ - printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n"); - } - } - umsdos_patch_inode(inode,dir,emd_pos); - } - if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode); -if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n"); + struct inode *dir, + struct inode *inode, + struct umsdos_dirent *entry, + off_t emd_pos) +{ + /* + This function modify the state of a dir inode. It decides + if the dir is a umsdos dir or a dos dir. This is done + deeper in umsdos_patch_inode() called at the end of this function. + + umsdos_patch_inode() may block because it is doing disk access. + At the same time, another process may get here to initialise + the same dir inode. There is 3 cases. + + 1-The inode is already initialised. We do nothing. + 2-The inode is not initialised. We lock access and do it. + 3-Like 2 but another process has lock the inode, so we try + to lock it and right after check if initialisation is still + needed. + + + Thanks to the mem option of the kernel command line, it was + possible to consistently reproduce this problem by limiting + my mem to 4 meg and running X. + */ + /* + Do this only if the inode is freshly read, because we will lose + the current (updated) content. + */ + /* + A lookup of a mount point directory yield the inode into + the other fs, so we don't care about initialising it. iget() + does this automatically. + */ + if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){ + if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode); + if (!umsdos_isinit(inode)){ + /* #Specification: umsdos / lookup / inode info + After successfully reading an inode from the MSDOS + filesystem, we use the EMD file to complete it. + We update the following field. + + uid, gid, atime, ctime, mtime, mode. + + We rely on MSDOS for mtime. If the file + was modified during an MSDOS session, at least + mtime will be meaningful. We do this only for regular + file. + + We don't rely on MSDOS for mtime for directory because + the MSDOS directory date is creation time (strange + MSDOS behavior) which fit nowhere in the three UNIX + time stamp. + */ + if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime; + inode->i_mode = entry->mode; + inode->i_rdev = to_kdev_t(entry->rdev); + inode->i_atime = entry->atime; + inode->i_ctime = entry->ctime; + inode->i_mtime = entry->mtime; + inode->i_uid = entry->uid; + inode->i_gid = entry->gid; + /* #Specification: umsdos / conversion mode + The msdos fs can do some inline conversion + of the data of a file. It can translate + silently from MsDOS text file format to Unix + one (crlf -> lf) while reading, and the reverse + while writing. This is activated using the mount + option conv=.... + + This is not useful for Linux file in promoted + directory. It can even be harmful. For this + reason, the binary (no conversion) mode is + always activated. + */ + /* #Specification: umsdos / conversion mode / todo + A flag could be added to file and directories + forcing an automatic conversion mode (as + done with the msdos fs). + + This flag could be setup on a directory basis + (instead of file) and all file in it would + logically inherited. If the conversion mode + is active (conv=) then the i_binary flag would + be left untouched in those directories. + + It was proposed that the sticky bit was used + to set this. The problem is that new file would + be written incorrectly. The other problem is that + the sticky bit has a meaning for directories. So + another bit should be used (there is some space + in the EMD file for it) and a special utilities + would be used to assign the flag to a directory). + I don't think it is useful to assign this flag + on a single file. + */ + + MSDOS_I(inode)->i_binary = 1; + /* #Specification: umsdos / i_nlink + The nlink field of an inode is maintain by the MSDOS file system + for directory and by UMSDOS for other file. The logic is that + MSDOS is already figuring out what to do for directories and + does nothing for other files. For MSDOS, there are no hard link + so all file carry nlink==1. UMSDOS use some info in the + EMD file to plug the correct value. + */ + if (!S_ISDIR(entry->mode)){ + if (entry->nlink > 0){ + inode->i_nlink = entry->nlink; + }else{ + printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n"); } + } + umsdos_patch_inode(inode,dir,emd_pos); + } + if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode); + if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n"); + } } struct UMSDOS_DIRENT_K{ - off_t f_pos; /* will hold the offset of the entry in EMD */ - ino_t ino; + off_t f_pos; /* will hold the offset of the entry in EMD */ + ino_t ino; }; /* - Just to record the offset of one entry. + Just to record the offset of one entry. */ static int umsdos_filldir_k( - void * buf, - const char * name, - int name_len, - off_t offset, - ino_t ino) -{ - struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf; - d->f_pos = offset; - d->ino = ino; - return 0; + void * buf, + const char *name, + int len, + off_t offset, + ino_t ino) +{ + struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf; + d->f_pos = offset; + d->ino = ino; + return 0; } struct UMSDOS_DIR_SEARCH{ - struct umsdos_dirent *entry; - int found; - ino_t search_ino; + struct umsdos_dirent *entry; + int found; + ino_t search_ino; }; static int umsdos_dir_search ( - void * buf, - const char * name, - int name_len, - off_t offset, - ino_t ino) -{ - int ret = 0; - struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf; - if (d->search_ino == ino){ - d->found = 1; - memcpy (d->entry->name,name,name_len); - d->entry->name[name_len] = '\0'; - d->entry->name_len = name_len; - ret = 1; /* So fat_readdir will terminate */ - } - return ret; + void * buf, + const char *name, + int len, + off_t offset, + ino_t ino) +{ + int ret = 0; + struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf; + if (d->search_ino == ino){ + d->found = 1; + memcpy (d->entry->name,name,len); + d->entry->name[len] = '\0'; + d->entry->name_len = len; + ret = 1; /* So fat_readdir will terminate */ + } + return ret; } /* - Locate entry of an inode in a directory. - Return 0 or a negative error code. - - Normally, this function must succeed. It means a strange corruption - in the file system if not. + Locate entry of an inode in a directory. + Return 0 or a negative error code. + + Normally, this function must succeed. It means a strange corruption + in the file system if not. */ int umsdos_inode2entry ( - struct inode *dir, - struct inode *inode, - struct umsdos_dirent *entry) /* Will hold the entry */ -{ - int ret = -ENOENT; - if (inode == pseudo_root){ - /* - Quick way to find the name. - Also umsdos_readdir_x won't show /linux anyway - */ - memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1); - entry->name_len = UMSDOS_PSDROOT_LEN; - ret = 0; - }else{ - struct inode *emddir = umsdos_emd_dir_lookup(dir,0); - iput (emddir); - if (emddir == NULL){ - /* This is a DOS directory */ - struct UMSDOS_DIR_SEARCH bufk; - struct file filp; - filp.f_reada = 1; - filp.f_pos = 0; - bufk.entry = entry; - bufk.search_ino = inode->i_ino; - fat_readdir (dir,&filp,&bufk,umsdos_dir_search); - if (bufk.found){ - ret = 0; - inode->u.umsdos_i.i_dir_owner = dir->i_ino; - inode->u.umsdos_i.i_emd_owner = 0; - umsdos_setup_dir_inode(inode); - } - }else{ - /* skip . and .. see umsdos_readdir_x() */ - struct file filp; - filp.f_reada = 1; - filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; - while (1){ - struct UMSDOS_DIRENT_K bufk; - if (umsdos_readdir_x(dir,&filp,&bufk - ,1,entry,0,umsdos_filldir_k) < 0){ - printk ("UMSDOS: can't locate inode %ld in EMD file???\n" - ,inode->i_ino); - break; - }else if (bufk.ino == inode->i_ino){ - ret = 0; - umsdos_lookup_patch (dir,inode,entry,bufk.f_pos); - break; - } - } - } + struct inode *dir, + struct inode *inode, + struct umsdos_dirent *entry) /* Will hold the entry */ +{ + int ret = -ENOENT; + if (pseudo_root && inode == pseudo_root){ + /* + Quick way to find the name. + Also umsdos_readdir_x won't show /linux anyway + */ + memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1); + entry->name_len = UMSDOS_PSDROOT_LEN; + ret = 0; + }else{ + struct inode *emddir = umsdos_emd_dir_lookup(dir,0); + iput (emddir); + if (emddir == NULL){ + /* This is a DOS directory */ + struct UMSDOS_DIR_SEARCH bufk; + struct file filp; + Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n")); + filp.f_reada = 1; + filp.f_pos = 0; + bufk.entry = entry; + bufk.search_ino = inode->i_ino; + fat_readdir (&filp,&bufk,umsdos_dir_search); + if (bufk.found){ + ret = 0; + inode->u.umsdos_i.i_dir_owner = dir->i_ino; + inode->u.umsdos_i.i_emd_owner = 0; + umsdos_setup_dir_inode(inode); + } + }else{ + /* skip . and .. see umsdos_readdir_x() */ + struct file filp; + filp.f_reada = 1; + filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; + Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n")); + while (1){ + struct UMSDOS_DIRENT_K bufk; + if (umsdos_readdir_x(dir,&filp,&bufk + ,1,entry,0,umsdos_filldir_k) < 0){ + printk ("UMSDOS: can't locate inode %ld in EMD file???\n" + ,inode->i_ino); + break; + }else if (bufk.ino == inode->i_ino){ + ret = 0; + umsdos_lookup_patch (dir,inode,entry,bufk.f_pos); + break; } - return ret; + } + } + } + return ret; } + + /* - Locate the parent of a directory and the info on that directory - Return 0 or a negative error code. + Locate the parent of a directory and the info on that directory + Return 0 or a negative error code. */ static int umsdos_locate_ancestor ( - struct inode *dir, - struct inode **result, - struct umsdos_dirent *entry) -{ - int ret; - umsdos_patch_inode (dir,NULL,0); - ret = umsdos_real_lookup (dir,"..",2,result); - PRINTK (("result %d %p ",ret,*result)); - if (ret == 0){ - struct inode *adir = *result; - ret = umsdos_inode2entry (adir,dir,entry); - } - PRINTK (("\n")); - return ret; -} -/* - Build the path name of an inode (relative to the file system. - This function is need to set (pseudo) hard link. - - It uses the same strategy as the standard getcwd(). + struct inode *dir, + struct inode **result, + struct umsdos_dirent *entry) +{ + int ret; + + umsdos_patch_inode (dir,NULL,0); + /* FIXME */ + ret = compat_umsdos_real_lookup (dir,"..",2,result); + Printk (("result %d %p ",ret,*result)); + if (ret == 0){ + struct inode *adir = *result; + ret = umsdos_inode2entry (adir,dir,entry); + } + Printk (("\n")); + return ret; +} +/* + Build the path name of an inode (relative to the file system. + This function is need to set (pseudo) hard link. + + It uses the same strategy as the standard getcwd(). */ int umsdos_locate_path ( - struct inode *inode, - char *path) + struct inode *inode, + char *path) { - int ret = 0; - struct inode *dir = inode; - char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - if (bpath == NULL){ - ret = -ENOMEM; - }else{ - struct umsdos_dirent entry; - char *ptbpath = bpath+PATH_MAX-1; - *ptbpath = '\0'; - PRINTK (("locate_path mode %x ",inode->i_mode)); - if (!S_ISDIR(inode->i_mode)){ - ret = umsdos_get_dirowner (inode,&dir); - PRINTK (("locate_path ret %d ",ret)); - if (ret == 0){ - ret = umsdos_inode2entry (dir,inode,&entry); - if (ret == 0){ - ptbpath -= entry.name_len; - memcpy (ptbpath,entry.name,entry.name_len); - PRINTK (("ptbpath :%s: ",ptbpath)); - } - } - }else{ - atomic_inc(&dir->i_count); - } - if (ret == 0){ - while (dir != dir->i_sb->s_mounted){ - struct inode *adir; - ret = umsdos_locate_ancestor (dir,&adir,&entry); - iput (dir); - dir = NULL; - PRINTK (("ancestor %d ",ret)); - if (ret == 0){ - *--ptbpath = '/'; - ptbpath -= entry.name_len; - memcpy (ptbpath,entry.name,entry.name_len); - dir = adir; - PRINTK (("ptbpath :%s: ",ptbpath)); - }else{ - break; - } - } - } - strcpy (path,ptbpath); - kfree (bpath); + int ret = 0; + struct inode *dir = inode; + struct inode *root_inode; + char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL); + root_inode = iget(inode->i_sb,UMSDOS_ROOT_INO); + if (bpath == NULL){ + ret = -ENOMEM; + }else{ + struct umsdos_dirent entry; + char *ptbpath = bpath+PATH_MAX-1; + *ptbpath = '\0'; + Printk (("locate_path mode %x ",inode->i_mode)); + if (!S_ISDIR(inode->i_mode)){ + ret = umsdos_get_dirowner (inode,&dir); + Printk (("locate_path ret %d ",ret)); + if (ret == 0){ + ret = umsdos_inode2entry (dir,inode,&entry); + if (ret == 0){ + ptbpath -= entry.name_len; + memcpy (ptbpath,entry.name,entry.name_len); + Printk (("ptbpath :%s: ",ptbpath)); } - PRINTK (("\n")); + } + }else{ + dir->i_count++; + } + if (ret == 0){ + while (dir != root_inode){ + struct inode *adir; + ret = umsdos_locate_ancestor (dir,&adir,&entry); iput (dir); - return ret; + dir = NULL; + Printk (("ancestor %d ",ret)); + if (ret == 0){ + *--ptbpath = '/'; + ptbpath -= entry.name_len; + memcpy (ptbpath,entry.name,entry.name_len); + dir = adir; + Printk (("ptbpath :%s: ",ptbpath)); + }else{ + break; + } + } + } + strcpy (path,ptbpath); + kfree (bpath); + } + Printk (("\n")); + iput (dir); + return ret; } /* @@ -598,205 +676,262 @@ */ int umsdos_is_pseudodos ( struct inode *dir, - const char *name, - int len) + struct dentry *dentry) { - /* #Specification: pseudo root / DOS hard coded - The pseudo sub-directory DOS in the pseudo root is hard coded. - The name is DOS. This is done this way to help standardised - the umsdos layout. The idea is that from now on /DOS is - a reserved path and nobody will think of using such a path - for a package. - */ - return dir == pseudo_root - && len == 3 - && name[0] == 'D' && name[1] == 'O' && name[2] == 'S'; + /* #Specification: pseudo root / DOS hard coded + The pseudo sub-directory DOS in the pseudo root is hard coded. + The name is DOS. This is done this way to help standardised + the umsdos layout. The idea is that from now on /DOS is + a reserved path and nobody will think of using such a path + for a package. + */ + return pseudo_root + && dir == pseudo_root + && dentry->d_name.len == 3 + && dentry->d_name.name[0] == 'D' + && dentry->d_name.name[1] == 'O' + && dentry->d_name.name[2] == 'S'; } + /* - Check if a file exist in the current directory. - Return 0 if ok, negative error code if not (ex: -ENOENT). + Check if a file exist in the current directory. + Return 0 if ok, negative error code if not (ex: -ENOENT). */ static int umsdos_lookup_x ( - struct inode *dir, - const char *name, - int len, - struct inode **result, /* Will hold inode of the file, if successful */ - int nopseudo) /* Don't care about pseudo root mode */ -{ - int ret = -ENOENT; - *result = NULL; - umsdos_startlookup(dir); - if (len == 1 && name[0] == '.'){ - *result = dir; - atomic_inc(&dir->i_count); - ret = 0; - }else if (len == 2 && name[0] == '.' && name[1] == '.'){ - if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){ - /* #Specification: pseudo root / .. in real root - Whenever a lookup is those in the real root for - the directory .., and pseudo root is active, the - pseudo root is returned. - */ - ret = 0; - *result = pseudo_root; - atomic_inc(&pseudo_root->i_count); - }else{ - /* #Specification: locating .. / strategy - We use the msdos filesystem to locate the parent directory. - But it is more complicated than that. - - We have to step back even further to - get the parent of the parent, so we can get the EMD - of the parent of the parent. Using the EMD file, we can - locate all the info on the parent, such a permissions - and owner. - */ - ret = umsdos_real_lookup (dir,"..",2,result); - PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result)); - if (ret == 0 - && *result != dir->i_sb->s_mounted - && *result != pseudo_root){ - struct inode *aadir; - struct umsdos_dirent entry; - ret = umsdos_locate_ancestor (*result,&aadir,&entry); - iput (aadir); - } - } - }else if (umsdos_is_pseudodos(dir,name,len)){ - /* #Specification: pseudo root / lookup(DOS) - A lookup of DOS in the pseudo root will always succeed - and return the inode of the real root. - */ - *result = dir->i_sb->s_mounted; - atomic_inc(&((*result)->i_count)); - ret = 0; - }else{ - struct umsdos_info info; - ret = umsdos_parse (name,len,&info); - if (ret == 0) ret = umsdos_findentry (dir,&info,0); - PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret - ,info.fake.len)); - if (ret == 0){ - /* #Specification: umsdos / lookup - A lookup for a file is done in two step. First, we locate - the file in the EMD file. If not present, we return - an error code (-ENOENT). If it is there, we repeat the - operation on the msdos file system. If this fails, it means - that the file system is not in sync with the emd file. - We silently remove this entry from the emd file, - and return ENOENT. - */ - struct inode *inode; - ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result); - inode = *result; - if (inode == NULL){ - printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n" - ,info.fake.fname); - umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode)); - }else{ - umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - PRINTK (("lookup ino %ld flags %d\n",inode->i_ino - ,info.entry.flags)); - if (info.entry.flags & UMSDOS_HLINK){ - ret = umsdos_hlink2inode (inode,result); - } - if (*result == pseudo_root && !nopseudo){ - /* #Specification: pseudo root / dir lookup - For the same reason as readdir, a lookup in /DOS for - the pseudo root directory (linux) will fail. - */ - /* - This has to be allowed for resolving hard link - which are recorded independently of the pseudo-root - mode. - */ - iput (pseudo_root); - *result = NULL; - ret = -ENOENT; - } - } - } + struct inode *dir, + struct dentry *dentry, + int nopseudo)/* Don't care about pseudo root mode */ +{ + int ret = -ENOENT; + struct inode *root_inode; + struct inode *pseudo_root_inode=NULL; + int len = dentry->d_name.len; + const char *name = dentry->d_name.name; + root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO); + /* pseudo_root_inode = iget( ... ) ? */ + dentry->d_inode = NULL; + umsdos_startlookup(dir); + if (len == 1 && name[0] == '.'){ + dentry->d_inode = dir; + dir->i_count++; + ret = 0; + }else if (len == 2 && name[0] == '.' && name[1] == '.'){ + if (pseudo_root && dir == pseudo_root_inode){ + /* #Specification: pseudo root / .. in real root + Whenever a lookup is those in the real root for + the directory .., and pseudo root is active, the + pseudo root is returned. + */ + ret = 0; + dentry->d_inode = pseudo_root; + pseudo_root->i_count++; + }else{ + /* #Specification: locating .. / strategy + We use the msdos filesystem to locate the parent directory. + But it is more complicated than that. + + We have to step back even further to + get the parent of the parent, so we can get the EMD + of the parent of the parent. Using the EMD file, we can + locate all the info on the parent, such a permissions + and owner. + */ + + ret = compat_umsdos_real_lookup (dir,"..",2,&dentry->d_inode); + Printk (("ancestor ret %d dir %p *result %p ",ret,dir,dentry->d_inode)); + if (ret == 0 + && dentry->d_inode != root_inode + && dentry->d_inode != pseudo_root){ + struct inode *aadir; + struct umsdos_dirent entry; + ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry); + iput (aadir); + } + } + }else if (umsdos_is_pseudodos(dir,dentry)){ + /* #Specification: pseudo root / lookup(DOS) + A lookup of DOS in the pseudo root will always succeed + and return the inode of the real root. + */ + dentry->d_inode = root_inode; + (dentry->d_inode)->i_count++; + ret = 0; + }else{ + struct umsdos_info info; + ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); + if (ret == 0) ret = umsdos_findentry (dir,&info,0); + Printk (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret + ,info.fake.len)); + if (ret == 0){ + /* #Specification: umsdos / lookup + A lookup for a file is done in two step. First, we locate + the file in the EMD file. If not present, we return + an error code (-ENOENT). If it is there, we repeat the + operation on the msdos file system. If this fails, it means + that the file system is not in sync with the emd file. + We silently remove this entry from the emd file, + and return ENOENT. + */ + struct inode *inode; + + ret = compat_umsdos_real_lookup (dir,info.fake.fname,info.fake.len,&inode); + + Printk (("umsdos_lookup_x: compat_umsdos_real_lookup for %25s returned %d with inode=%p\n", info.fake.fname, ret, inode)); + + if (inode == NULL){ + printk (KERN_WARNING "UMSDOS: Erase entry %s, out of sync with MsDOS\n" + ,info.fake.fname); + umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode)); + }else{ + Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%d\n",inode->i_ino)); + + /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */ + dentry->d_inode = iget(dir->i_sb, inode->i_ino); + + umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); + Printk (("lookup ino %ld flags %d\n",inode->i_ino + ,info.entry.flags)); + if (info.entry.flags & UMSDOS_HLINK){ + Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ HLINK\n")); + ret = umsdos_hlink2inode (inode,&dentry->d_inode); } - umsdos_endlookup(dir); - iput (dir); - return ret; + if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo){ + /* #Specification: pseudo root / dir lookup + For the same reason as readdir, a lookup in /DOS for + the pseudo root directory (linux) will fail. + */ + /* + This has to be allowed for resolving hard link + which are recorded independently of the pseudo-root + mode. + */ + Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n")); + iput (pseudo_root); + dentry->d_inode = NULL; + ret = -ENOENT; + } + } + } + } + umsdos_endlookup(dir); + iput (dir); + Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret)); + return ret; } + + /* - Check if a file exist in the current directory. - Return 0 if ok, negative error code if not (ex: -ENOENT). + Check if a file exist in the current directory. + Return 0 if ok, negative error code if not (ex: -ENOENT). + + */ int UMSDOS_lookup ( - struct inode *dir, - const char *name, - int len, - struct inode **result) /* Will hold inode of the file, if successful */ + struct inode *dir, + struct dentry *dentry) { - return umsdos_lookup_x(dir,name,len,result,0); + return umsdos_lookup_x(dir,dentry,0); } + + + /* - Locate the inode pointed by a (pseudo) hard link - Return 0 if ok, a negative error code if not. + Locate the inode pointed by a (pseudo) hard link + Return 0 if ok, a negative error code if not. */ int umsdos_hlink2inode (struct inode *hlink, struct inode **result) { - int ret = -EIO; - char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - *result = NULL; - if (path == NULL){ - ret = -ENOMEM; - iput (hlink); - }else{ - struct file filp; - filp.f_reada = 1; - filp.f_pos = 0; - PRINTK (("hlink2inode ")); - if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size) - ==hlink->i_size){ - struct inode *dir; - char *pt = path; - dir = hlink->i_sb->s_mounted; - path[hlink->i_size] = '\0'; - iput (hlink); - atomic_inc(&dir->i_count); - while (1){ - char *start = pt; - int len; - while (*pt != '\0' && *pt != '/') pt++; - len = (int)(pt - start); - if (*pt == '/') *pt++ = '\0'; - if (dir->u.umsdos_i.i_emd_dir == 0){ - /* This is a DOS directory */ - ret = umsdos_rlookup_x(dir,start,len,result,1); - }else{ - ret = umsdos_lookup_x(dir,start,len,result,1); - } - PRINTK (("h2n lookup :%s: -> %d ",start,ret)); - if (ret == 0 && *pt != '\0'){ - dir = *result; - }else{ - break; - } - } - }else{ - iput (hlink); - } - PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result)); - kfree (path); - } - return ret; + struct inode *root_inode; + int ret = -EIO; + struct dentry *dentry_src, *dentry_dst; + char *path; + +#if 0 /* FIXME: DELME */ + Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n")); + return -ENOENT; /* /mn/ FIXME just for test */ +#endif + + path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); + + root_inode = iget(hlink->i_sb,UMSDOS_ROOT_INO); + *result = NULL; + if (path == NULL){ + ret = -ENOMEM; + iput (hlink); + }else{ + struct file filp; + loff_t offs = 0; + + dentry_src = creat_dentry ("hlink-mn", 8, hlink); + + memset (&filp, 0, sizeof (filp)); + + filp.f_pos = 0; + filp.f_reada = 1; + filp.f_flags = O_RDONLY; + filp.f_dentry = dentry_src; + filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + + Printk (("hlink2inode ")); + if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size) + { + struct inode *dir; + char *pt = path; + dir = root_inode; + path[hlink->i_size] = '\0'; +/* iput (hlink); / * FIXME! /mn/ */ + dir->i_count++; + while (1) + { + char *start = pt; + int len; + while (*pt != '\0' && *pt != '/') pt++; + len = (int)(pt - start); + if (*pt == '/') *pt++ = '\0'; + /* FIXME. /mn/ fixed ? */ + + dentry_dst = creat_dentry (start, len, NULL); + + if (dir->u.umsdos_i.i_emd_dir == 0){ + /* This is a DOS directory */ + + Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %20s\n", dentry_dst->d_name.name)); + ret = umsdos_rlookup_x(dir,dentry_dst,1); + }else{ + Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %20s\n", dentry_dst->d_name.name)); + ret = umsdos_lookup_x(dir,dentry_dst,1); + } + Printk ((" returned %d\n", ret)); + + Printk (("h2n lookup :%s: -> %d ",start,ret)); + if (ret == 0 && *pt != '\0'){ + dir = dentry_dst->d_inode; + }else{ + break; + } + } + }else{ + Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n")); + iput (hlink); /* FIXME */ + } + Printk (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result)); + kfree (path); + } + return ret; } + static struct file_operations umsdos_dir_operations = { NULL, /* lseek - default */ - UMSDOS_dir_read, /* read */ + UMSDOS_dir_read, /* read */ NULL, /* write - bad */ - UMSDOS_readdir, /* readdir */ + UMSDOS_readdir, /* readdir */ NULL, /* poll - default */ - UMSDOS_ioctl_dir, /* ioctl - default */ + UMSDOS_ioctl_dir, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ - NULL /* fsync */ + NULL /* fsync */ /* in original NULL. changed to file_fsync. FIXME? /mn/ */ }; struct inode_operations umsdos_dir_inode_operations = { @@ -811,14 +946,17 @@ UMSDOS_mknod, /* mknod */ UMSDOS_rename, /* rename */ NULL, /* readlink */ - NULL, /* readpage */ + NULL, /* followlink */ + generic_readpage, /* readpage */ /* in original NULL. changed to generic_readpage. FIXME? /mn/ */ NULL, /* writepage */ - NULL, /* bmap */ + fat_bmap, /* bmap */ /* in original NULL. changed to fat_bmap. FIXME? /mn/ */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL, /* revalidate */ + }; - - diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.1.86/linux/fs/umsdos/emd.c Mon Dec 1 10:34:11 1997 +++ linux/fs/umsdos/emd.c Thu Feb 12 13:36:57 1998 @@ -17,36 +17,141 @@ #include +#include + #define PRINTK(x) #define Printk(x) printk x /* - Read a file into kernel space memory -*/ -long umsdos_file_read_kmem (struct inode *inode, - struct file *filp, - char *buf, - unsigned long count) -{ - int ret; - mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = fat_file_read(inode,filp,buf,count); - set_fs (old_fs); - return ret; + * makes dentry. for name name with length len. /mn/ + * if inode is not NULL, puts it also. + * + */ + +struct dentry *creat_dentry (const char *name, const int len, const struct inode *inode) +{ + struct dentry *ret, *parent=NULL; /* FIXME /mn/: whatis parent ?? */ + struct qstr qname; + + if (inode) + Printk (("/mn/ creat_dentry: creating dentry with inode=%d for %20s\n", inode->i_ino, name)); + else + Printk (("/mn/ creat_dentry: creating empty dentry for %20s\n", name)); + + qname.name = name; + qname.len = len; + qname.hash = 0; + + ret = d_alloc (parent,&qname); /* create new dentry */ + ret->d_inode = inode; +} + + + +/* + * Read a file into kernel space memory + * returns how many bytes read (from fat_file_read) + */ + +ssize_t umsdos_file_read_kmem (struct inode *emd_dir, + struct file *filp, + char *buf, + size_t count, + loff_t *offs + ) +{ + int ret; + + struct dentry *old_dentry; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + + old_dentry=filp->f_dentry; /* save it */ + filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); + *offs = filp->f_pos; + + Printk ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%ld, offs=%p\n", filp, buf, count, offs)); + Printk ((KERN_DEBUG " using emd=%d\n", emd_dir->i_ino)); + Printk ((KERN_DEBUG " inode=%d, i_size=%d\n", filp->f_dentry->d_inode->i_ino,filp->f_dentry->d_inode->i_size)); + Printk ((KERN_DEBUG " ofs=%ld\n", *offs)); + Printk ((KERN_DEBUG " f_pos=%ld\n", filp->f_pos)); + Printk ((KERN_DEBUG " name=%12s\n", filp->f_dentry->d_name.name)); + Printk ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + Printk ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + Printk ((KERN_DEBUG " f_owner=%d\n", filp->f_owner)); + Printk ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); + Printk ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + + ret = fat_file_read(filp,buf,count,offs); + Printk ((KERN_DEBUG "fat_file_read returned with %ld!\n", ret)); + + filp->f_pos = *offs; /* we needed *filp only for this? grrrr... /mn/ */ + /* FIXME: I have no idea what f_pos is used for. It seems to be used this way before offs was introduced. + this probably needs fixing /mn/ */ + + filp->f_dentry=old_dentry; /* restore orig. dentry (it is dentry of file we need info about. Dunno why it gets passed to us + since we have no use for it, expect to store totally unrelated data of offset of EMD_FILE + end not directory in it. But what the hell now... fat_file_read requires it also, but prolly expects + it to be file* of EMD not file we want to read EMD entry about... ugh. complicated to explain :) /mn/ */ + + /* FIXME: we probably need to destroy originl filp->f_dentry first ? Do we ? And how ? this way we leave all sorts of dentries, inodes etc. lying around */ + /* Also FIXME: all the same problems in umsdos_file_write_kmem */ + + Printk ((KERN_DEBUG " (ret) using emd=%d\n", emd_dir->i_ino)); + Printk ((KERN_DEBUG " (ret) inode=%d, i_size=%d\n", filp->f_dentry->d_inode->i_ino,filp->f_dentry->d_inode->i_size)); + Printk ((KERN_DEBUG " (ret) ofs=%ld\n", *offs)); + Printk ((KERN_DEBUG " (ret) f_pos=%ld\n", filp->f_pos)); + Printk ((KERN_DEBUG " (ret) name=%12s\n", filp->f_dentry->d_name.name)); + Printk ((KERN_DEBUG " (ret) i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + Printk ((KERN_DEBUG " (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + Printk ((KERN_DEBUG " (ret) f_owner=%d\n", filp->f_owner)); + Printk ((KERN_DEBUG " (ret) f_version=%ld\n", filp->f_version)); + Printk ((KERN_DEBUG " (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + +#if 0 + { + struct umsdos_dirent *mydirent=buf; + + Printk ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); + Printk ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); + Printk ((KERN_DEBUG " (DDD) name=>%20s<\n",mydirent->name)); + } +#endif + + set_fs (old_fs); + return ret; } + + /* Write to a file from kernel space */ -long umsdos_file_write_kmem (struct inode *inode, - struct file *filp, - const char *buf, - unsigned long count) +ssize_t umsdos_file_write_kmem (struct inode *emd_dir, + struct file *filp, + const char *buf, + size_t count, + loff_t *offs + ) { int ret; mm_segment_t old_fs = get_fs(); + struct dentry *old_dentry; /* FIXME /mn/: whatis parent ?? */ + set_fs (KERNEL_DS); - ret = fat_file_write(inode,filp,buf,count); + ret = fat_file_write(filp,buf,count,offs); + + old_dentry=filp->f_dentry; /* save it */ + filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); + + *offs = filp->f_pos; + + ret = fat_file_write (filp,buf,count,offs); + PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret)); + + filp->f_pos = *offs; + filp->f_dentry=old_dentry; + set_fs (old_fs); return ret; } @@ -58,12 +163,16 @@ Return 0 if ok, a negative error code if not. */ -long umsdos_emd_dir_write (struct inode *emd_dir, - struct file *filp, - char *buf, /* buffer in kernel memory, not in user space */ - unsigned long count) +ssize_t umsdos_emd_dir_write (struct inode *emd_dir, + struct file *filp, + char *buf, /* buffer in kernel memory, not in user space */ + size_t count, + loff_t *offs + ) { int written; + loff_t myofs=0; + #ifdef __BIG_ENDIAN struct umsdos_dirent *d = (struct umsdos_dirent *)buf; #endif @@ -78,7 +187,11 @@ d->rdev = cpu_to_le16 (d->rdev); d->mode = cpu_to_le16 (d->mode); #endif - written = umsdos_file_write_kmem (emd_dir,filp,buf,count); + + if (offs) myofs=*offs; /* if offs is not NULL, read it */ + written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs); + if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ + #ifdef __BIG_ENDIAN d->nlink = le16_to_cpu (d->nlink); d->uid = le16_to_cpu (d->uid); @@ -91,25 +204,36 @@ #endif return written != count ? -EIO : 0; } + + + /* - Read a block of bytes from one EMD file. - The block of data is NOT in user space. - Return 0 if ok, -EIO if any error. -*/ -long umsdos_emd_dir_read (struct inode *emd_dir, + * Read a block of bytes from one EMD file. + * The block of data is NOT in user space. + * Return 0 if ok, -EIO if any error. + */ + +ssize_t umsdos_emd_dir_read (struct inode *emd_dir, struct file *filp, char *buf, /* buffer in kernel memory, not in user space */ - unsigned long count) + size_t count, + loff_t *offs + ) { + loff_t myofs=0; long int ret = 0; int sizeread; + + #ifdef __BIG_ENDIAN struct umsdos_dirent *d = (struct umsdos_dirent *)buf; #endif + + if (offs) myofs=*offs; /* if offs is not NULL, read it */ filp->f_flags = 0; - sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count); + sizeread = umsdos_file_read_kmem (emd_dir, filp, buf, count, &myofs); if (sizeread != count){ - printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %ld)\n" + printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n" ,filp->f_pos,sizeread,count); ret = -EIO; } @@ -123,49 +247,105 @@ d->rdev = le16_to_cpu (d->rdev); d->mode = le16_to_cpu (d->mode); #endif + if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ return ret; } + + + + +/* + Locate the EMD file in a directory . + + Return NULL if error. If ok, dir->u.umsdos_i.emd_inode +*/ +struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat) +{ + struct inode *ret = NULL; + int res; + Printk (("Entering umsdos_emd_dir_lookup\n")); + if (dir->u.umsdos_i.i_emd_dir != 0){ + ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); + Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n" + ,dir->u.umsdos_i.i_emd_dir,ret)); + } else { + Printk ((KERN_DEBUG "umsdos /mn/: Looking for %20s -", UMSDOS_EMD_FILE)); + res = compat_umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, &ret); + Printk ((KERN_DEBUG "-returned %d\n", res)); + Printk ((KERN_DEBUG "emd_dir_lookup ")); + if (ret != NULL){ + Printk ((KERN_DEBUG "Found --linux ")); + dir->u.umsdos_i.i_emd_dir = ret->i_ino; + } else if (creat) { + int code; + Printk ((KERN_ERR " * ERROR * /mn/: creat not yet implemented!!!!" )); + Printk ((KERN_DEBUG "avant create ")); + atomic_inc(&dir->i_count); + + code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN + ,S_IFREG|0777,&ret); + Printk ((KERN_DEBUG "Creat EMD code %d ret %x ",code,ret)); + if (ret != NULL){ + dir->u.umsdos_i.i_emd_dir = ret->i_ino; + }else{ + printk ("UMSDOS: Can't create EMD file\n"); + } + } + + if (ret != NULL){ + /* Disable UMSDOS_notify_change() for EMD file */ + ret->u.umsdos_i.i_emd_owner = 0xffffffff; + } + + } + + Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret)); + if (ret != NULL) Printk ((KERN_DEBUG " debug : returning ino=%d\n",ret->i_ino)); + return ret; +} + /* - Locate the EMD file in a directory and optionally, creates it. + creates an EMD file Return NULL if error. If ok, dir->u.umsdos_i.emd_inode */ -struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat) + +struct inode *umsdos_emd_dir_create(struct inode *dir, struct dentry *dentry,int mode) { struct inode *ret = NULL; if (dir->u.umsdos_i.i_emd_dir != 0){ ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); - PRINTK (("deja trouve %d %x [%d] " - ,dir->u.umsdos_i.i_emd_dir,ret, - atomic_read(&ret->i_count))); + Printk (("deja trouve %d %x",dir->u.umsdos_i.i_emd_dir,ret)); }else{ - umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret); - PRINTK (("emd_dir_lookup ")); - if (ret != NULL){ - PRINTK (("Find --linux ")); - dir->u.umsdos_i.i_emd_dir = ret->i_ino; - }else if (creat){ - int code; - PRINTK (("avant create ")); - atomic_inc(&dir->i_count); - code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN - ,S_IFREG|0777,&ret); - PRINTK (("Creat EMD code %d ret %x ",code,ret)); - if (ret != NULL){ - dir->u.umsdos_i.i_emd_dir = ret->i_ino; - }else{ - printk ("UMSDOS: Can't create EMD file\n"); - } - } + + int code; + Printk (("avant create ")); + dir->i_count++; + /* + code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN + ,S_IFREG|0777,&ret); + + FIXME, I think I need a new dentry here + */ + code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN, S_IFREG|0777, &ret); + Printk (("Creat EMD code %d ret %x ",code,ret)); + if (ret != NULL){ + dir->u.umsdos_i.i_emd_dir = ret->i_ino; + }else{ + printk ("UMSDOS: Can't create EMD file\n"); + } } + if (ret != NULL){ - /* Disable UMSDOS_notify_change() for EMD file */ - ret->u.umsdos_i.i_emd_owner = 0xffffffff; + /* Disable UMSDOS_notify_change() for EMD file */ + ret->u.umsdos_i.i_emd_owner = 0xffffffff; } return ret; } + + /* Read an entry from the EMD file. Support variable length record. @@ -176,18 +356,28 @@ struct file *filp, struct umsdos_dirent *entry) { - int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE); - if (ret == 0){ + int ret; + Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n")); + Printk (("umsdos_emd_dir_readentry /mn/: trying to lookup %12s (ino=%d) using EMD %d\n", filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, emd_dir->i_ino)); + + ret = umsdos_emd_dir_read(emd_dir, filp, (char*)entry, UMSDOS_REC_SIZE, NULL); + if (ret == 0){ /* note /mn/: is this wrong? ret is allways 0 or -EIO. but who knows. It used to work this way... */ /* Variable size record. Maybe, we have to read some more */ int recsize = umsdos_evalrecsize (entry->name_len); + Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: FIXME if %d > %d?\n",recsize, UMSDOS_REC_SIZE)); if (recsize > UMSDOS_REC_SIZE){ - ret = umsdos_emd_dir_read(emd_dir,filp - ,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE); + ret = umsdos_emd_dir_read(emd_dir, filp + ,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE,NULL); } } + Printk (("umsdos_emd_dir_readentry /mn/: returning %d.\n", ret)); return ret; } + + + + /* Write an entry in the EMD file. Return 0 if ok, -EIO if some error. @@ -202,6 +392,12 @@ struct file filp; struct umsdos_dirent *entry = &info->entry; struct umsdos_dirent entry0; + + Printk (("umsdos_writeentry /mn/: entering...\n")); + + Printk ((KERN_ERR "umsdos_writeentry /mn/: FIXME! this is READ ONLY FOR NOW. RETURNING...\n")); + return -EIO; + if (free_entry){ /* #Specification: EMD file / empty entries Unused entry in the EMD file are identify @@ -222,15 +418,20 @@ */ memset (entry->spare,0,sizeof(entry->spare)); } + + Printk (("umsdos_writeentry /mn/: if passed...\n")); + filp.f_pos = info->f_pos; filp.f_reada = 0; - ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize); + ret = umsdos_emd_dir_write(emd_dir, &filp,(char*)entry,info->recsize,NULL); if (ret != 0){ printk ("UMSDOS: problem with EMD file. Can't write\n"); }else{ dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_dirt = 1; + /* dir->i_dirt = 1; FIXME iput/dput ??? */ } + + Printk (("umsdos_writeentry /mn/: returning...\n")); return ret; } @@ -242,6 +443,10 @@ struct file filp; }; + + + + /* Fill the read buffer and take care of the byte remaining inside. Unread bytes are simply move to the beginning. @@ -256,6 +461,9 @@ int mustmove = buf->size - buf->pos; int mustread; int remain; + + Printk ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %d, buf=%p\n",inode->i_ino, buf)); + if (mustmove > 0){ memcpy (buf->buffer,buf->buffer+buf->pos,mustmove); } @@ -264,8 +472,8 @@ remain = inode->i_size - buf->filp.f_pos; if (remain < mustread) mustread = remain; if (mustread > 0){ - ret = umsdos_emd_dir_read (inode,&buf->filp,buf->buffer+mustmove - ,mustread); + ret = umsdos_emd_dir_read (inode, &buf->filp,buf->buffer+mustmove + ,mustread,NULL); if (ret == 0) buf->size = mustmove + mustread; }else if (mustmove){ buf->size = mustmove; @@ -274,6 +482,8 @@ return ret; } + + /* General search, locate a name in the EMD file or an empty slot to store it. if info->entry.name_len == 0, search the first empty @@ -308,6 +518,7 @@ record, multiple contiguous record are allocated. */ int ret = -ENOENT; + /* FIXME */ struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1); if (emd_dir != NULL){ struct umsdos_dirent *entry = &info->entry; @@ -320,10 +531,21 @@ }empty; /* Read several entries at a time to speed up the search */ struct find_buffer buf; - buf.pos = 0; - buf.size = 0; + struct dentry *dentry; + + memset (&buf.filp, 0, sizeof (buf.filp)); + + dentry = creat_dentry ("umsfind-mn", 10, emd_dir); + buf.filp.f_pos = 0; buf.filp.f_reada = 1; + buf.filp.f_flags = O_RDONLY; + buf.filp.f_dentry = dentry; + buf.filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + + buf.pos = 0; + buf.size = 0; + empty.found = 0; empty.posok = emd_dir->i_size; empty.onesize = 0; @@ -388,6 +610,7 @@ *pt_emd_dir = emd_dir; return ret; } + /* Add a new entry in the emd file Return 0 if ok or a negative error code. @@ -405,11 +628,12 @@ ret = -EEXIST; }else if (ret == -ENOENT){ ret = umsdos_writeentry(dir,emd_dir,info,0); - PRINTK (("umsdos_newentry EDM ret = %d\n",ret)); + Printk (("umsdos_newentry EDM ret = %d\n",ret)); } iput (emd_dir); return ret; } + /* Create a new hidden link. Return 0 if ok, an error code if not. @@ -475,15 +699,24 @@ */ int umsdos_isempty (struct inode *dir) { + struct dentry *dentry; + int ret = 2; struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0); /* If the EMD file does not exist, it is certainly empty :-) */ if (emd_dir != NULL){ struct file filp; /* Find an empty slot */ + memset (&filp, 0, sizeof (filp)); + + dentry = creat_dentry ("isempty-mn", 10, dir); + filp.f_pos = 0; filp.f_reada = 1; filp.f_flags = O_RDONLY; + filp.f_dentry = dentry; + filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + ret = 1; while (filp.f_pos < emd_dir->i_size){ struct umsdos_dirent entry; diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/file.c linux/fs/umsdos/file.c --- v2.1.86/linux/fs/umsdos/file.c Mon Jun 16 16:35:59 1997 +++ linux/fs/umsdos/file.c Thu Feb 12 13:36:57 1998 @@ -21,43 +21,57 @@ #define PRINTK(x) #define Printk(x) printk x + + /* Read a file into user space memory */ -static long UMSDOS_file_read( - struct inode *inode, +static ssize_t UMSDOS_file_read( struct file *filp, char *buf, - unsigned long count) + size_t count, + loff_t *ppos + ) { + struct dentry * dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + /* We have to set the access time because msdos don't care */ - int ret = fat_file_read(inode,filp,buf,count); + /* FIXME */ + int ret = fat_file_read(filp,buf,count,ppos); if (!IS_RDONLY(inode)){ inode->i_atime = CURRENT_TIME; + /* FIXME inode->i_dirt = 1; + */ } return ret; } + + /* Write a file from user space memory */ -static long UMSDOS_file_write( - struct inode *inode, +static ssize_t UMSDOS_file_write( struct file *filp, const char *buf, - unsigned long count) + size_t count, + loff_t *ppos) { - return fat_file_write(inode,filp,buf,count); + return fat_file_write(filp,buf,count,ppos); } + + /* Truncate a file to 0 length. */ static void UMSDOS_truncate(struct inode *inode) { - PRINTK (("UMSDOS_truncate\n")); + Printk (("UMSDOS_truncate\n")); fat_truncate (inode); inode->i_ctime = inode->i_mtime = CURRENT_TIME; - inode->i_dirt = 1; + + /*FIXME inode->i_dirt = 1; */ } /* Function for normal file system (512 bytes hardware sector size) */ @@ -86,18 +100,20 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ - UMSDOS_truncate,/* truncate */ + UMSDOS_truncate, /* truncate */ NULL, /* permission */ fat_smap /* smap */ }; + /* For other with larger and unaligned file system */ struct file_operations umsdos_file_operations_no_bmap = { NULL, /* lseek - default */ - UMSDOS_file_read, /* read */ - UMSDOS_file_write, /* write */ + UMSDOS_file_read, /* read */ + UMSDOS_file_write, /* write */ NULL, /* readdir - bad */ NULL, /* poll - default */ NULL, /* ioctl - default */ @@ -119,10 +135,11 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ - UMSDOS_truncate,/* truncate */ + UMSDOS_truncate, /* truncate */ NULL, /* permission */ NULL, /* smap */ }; diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v2.1.86/linux/fs/umsdos/inode.c Mon Jun 16 16:35:59 1997 +++ linux/fs/umsdos/inode.c Thu Feb 12 13:36:57 1998 @@ -19,96 +19,116 @@ #include #include -struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */ - /* directory. See UMSDOS_readdir_x() */ +struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */ + /* directory. See UMSDOS_readdir_x() */ /* #Specification: convention / PRINTK Printk and printk - Here is the convention for the use of printk inside fs/umsdos - - printk carry important message (error or status). - Printk is for debugging (it is a macro defined at the beginning of - most source. - PRINTK is a nulled Printk macro. - - This convention makes the source easier to read, and Printk easier - to shut off. + Here is the convention for the use of printk inside fs/umsdos + + printk carry important message (error or status). + Printk is for debugging (it is a macro defined at the beginning of + most source. + PRINTK is a nulled Printk macro. + + This convention makes the source easier to read, and Printk easier + to shut off. */ #define PRINTK(x) #define Printk(x) printk x - void UMSDOS_put_inode(struct inode *inode) { - PRINTK (("put inode %x owner %x pos %d dir %x\n",inode - ,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos - ,inode->u.umsdos_i.i_emd_dir)); - if (inode != NULL && inode == pseudo_root){ - printk ("Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n"); - } - fat_put_inode(inode); + Printk ((KERN_DEBUG "put inode %x (%d) owner %x pos %d dir %x\n",inode, inode->i_ino + ,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos + ,inode->u.umsdos_i.i_emd_dir)); + if (inode && pseudo_root && inode == pseudo_root){ + printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n"); + } + +#if 1 + fat_put_inode(inode); +#else + Printk ((KERN_WARNING "UMSDOS_put_inode: skipping ! FIXME /mn/\n")); +#endif } void UMSDOS_put_super(struct super_block *sb) { - msdos_put_super(sb); - MOD_DEC_USE_COUNT; + Printk (("UMSDOS_put_super: /mn/ entering\n")); + msdos_put_super(sb); + MOD_DEC_USE_COUNT; } -void UMSDOS_statfs(struct super_block *sb,struct statfs *buf, int bufsiz) -{ - fat_statfs(sb,buf,bufsiz); -} - /* - Call msdos_lookup, but set back the original msdos function table. - Return 0 if ok, or a negative error code if not. + Call msdos_lookup, but set back the original msdos function table. + Return 0 if ok, or a negative error code if not. */ int umsdos_real_lookup ( - struct inode *dir, - const char *name, - int len, - struct inode **result) /* Will hold inode of the file, if successful */ -{ - int ret; - atomic_inc(&dir->i_count); - ret = msdos_lookup (dir,name,len,result); - return ret; + struct inode *dir, + struct dentry *dentry + ) /* Will hold inode of the file, if successful */ +{ + int ret; + + Printk (("umsdos_real_lookup /mn/: looking for %s /",dentry->d_name.name)); + dir->i_count++; /* /mn/ what is this and why ? locking? */ + ret = msdos_lookup (dir,dentry); + Printk (("/ returned %d\n", ret)); + + return ret; } + /* - Complete the setup of an directory inode. - First, it completes the function pointers, then - it locates the EMD file. If the EMD is there, then plug the - umsdos function table. If not, use the msdos one. + Complete the setup of an directory inode. + First, it completes the function pointers, then + it locates the EMD file. If the EMD is there, then plug the + umsdos function table. If not, use the msdos one. */ void umsdos_setup_dir_inode (struct inode *inode) { - inode->u.umsdos_i.i_emd_dir = 0; - { - struct inode *emd_dir = umsdos_emd_dir_lookup (inode,0); - extern struct inode_operations umsdos_rdir_inode_operations; - inode->i_op = emd_dir != NULL - ? &umsdos_dir_inode_operations - : &umsdos_rdir_inode_operations; - iput (emd_dir); - } + inode->u.umsdos_i.i_emd_dir = 0; + { + struct inode *emd_dir = NULL; + extern struct inode_operations umsdos_rdir_inode_operations; + + emd_dir = umsdos_emd_dir_lookup (inode,0); + Printk (("umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n",inode,emd_dir)); + + if (emd_dir == NULL) { + Printk (("umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. NOT using EMD.\n")); + inode->i_op = &umsdos_rdir_inode_operations; + } else { + Printk (("umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. using EMD.\n")); + inode->i_op = &umsdos_dir_inode_operations; + } + + iput (emd_dir); + } } + + /* Add some info into an inode so it can find its owner quickly */ void umsdos_set_dirinfo( - struct inode *inode, - struct inode *dir, - off_t f_pos) -{ - struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1); - inode->u.umsdos_i.i_dir_owner = dir->i_ino; - inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; - iput (emd_owner); - inode->u.umsdos_i.pos = f_pos; + struct inode *inode, + struct inode *dir, + off_t f_pos) +{ + struct inode *emd_owner; + /* FIXME, I don't have a clue on this one */ + Printk (("umsdos_set_dirinfo: /mn/ FIXME: no clue\n")); + emd_owner = umsdos_emd_dir_lookup(dir,1); + inode->u.umsdos_i.i_dir_owner = dir->i_ino; + inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; + iput (emd_owner); + inode->u.umsdos_i.pos = f_pos; } + + /* Tells if an Umsdos inode has been "patched" once. Return != 0 if so. @@ -123,80 +143,94 @@ return atomic_read(&inode->i_count) > 1; #endif } + + /* - Connect the proper tables in the inode and add some info. + Connect the proper tables in the inode and add some info. */ void umsdos_patch_inode ( - struct inode *inode, - struct inode *dir, /* May be NULL */ - off_t f_pos) -{ - /* - This function is called very early to setup the inode, somewhat - too early (called by UMSDOS_read_inode). At this point, we can't - do to much, such as lookup up EMD files and so on. This causes - confusion in the kernel. This is why some initialisation - will be done when dir != NULL only. - - UMSDOS do run piggy back on top of msdos fs. It looks like something - is missing in the VFS to accommodate stacked fs. Still unclear what - (quite honestly). - - Well, maybe one! A new entry "may_unmount" which would allow - the stacked fs to allocate some inode permanently and release - them at the end. Doing that now introduce a problem. unmount - always fail because some inodes are in use. - */ - if (!umsdos_isinit(inode)){ - inode->u.umsdos_i.i_emd_dir = 0; - if (S_ISREG(inode->i_mode)){ - if (inode->i_op->bmap != NULL){ - inode->i_op = &umsdos_file_inode_operations; - }else{ - inode->i_op = &umsdos_file_inode_operations_no_bmap; - } - }else if (S_ISDIR(inode->i_mode)){ - if (dir != NULL){ - umsdos_setup_dir_inode(inode); - } - }else if (S_ISLNK(inode->i_mode)){ - inode->i_op = &umsdos_symlink_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 (dir != NULL){ - /* #Specification: inode / umsdos info - The first time an inode is seen (inode->i_count == 1), - the inode number of the EMD file which control this inode - is tagged to this inode. It allows operation such - as notify_change to be handled. - */ - /* - This is done last because it also control the - status of umsdos_isinit() - */ - umsdos_set_dirinfo (inode,dir,f_pos); - } - }else if (dir != NULL){ - /* - Test to see if the info is maintained. - This should be removed when the file system will be proven. - */ - struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1); - iput (emd_owner); - if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){ - printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld " - ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner); - } - } + struct inode *inode, + struct inode *dir, /* May be NULL */ + off_t f_pos) +{ + /* + This function is called very early to setup the inode, somewhat + too early (called by UMSDOS_read_inode). At this point, we can't + do to much, such as lookup up EMD files and so on. This causes + confusion in the kernel. This is why some initialisation + will be done when dir != NULL only. + + UMSDOS do run piggy back on top of msdos fs. It looks like something + is missing in the VFS to accommodate stacked fs. Still unclear what + (quite honestly). + + Well, maybe one! A new entry "may_unmount" which would allow + the stacked fs to allocate some inode permanently and release + them at the end. Doing that now introduce a problem. unmount + always fail because some inodes are in use. + */ + if (!umsdos_isinit(inode)){ + inode->u.umsdos_i.i_emd_dir = 0; + if (S_ISREG(inode->i_mode)){ + if (inode->i_op->bmap != NULL){ + Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); + inode->i_op = &umsdos_file_inode_operations; + }else{ + Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); + inode->i_op = &umsdos_file_inode_operations_no_bmap; + } + }else if (S_ISDIR(inode->i_mode)){ + if (dir != NULL){ + umsdos_setup_dir_inode(inode); + } + }else if (S_ISLNK(inode->i_mode)){ + Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n")); + inode->i_op = &umsdos_symlink_inode_operations; + }else if (S_ISCHR(inode->i_mode)){ + Printk (("umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n")); + inode->i_op = &chrdev_inode_operations; + }else if (S_ISBLK(inode->i_mode)){ + Printk (("umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n")); + inode->i_op = &blkdev_inode_operations; + }else if (S_ISFIFO(inode->i_mode)){ + Printk (("umsdos_patch_inode /mn/: uhm, init_fifo\n")); + init_fifo(inode); + } + if (dir != NULL){ + /* #Specification: inode / umsdos info + The first time an inode is seen (inode->i_count == 1), + the inode number of the EMD file which control this inode + is tagged to this inode. It allows operation such + as notify_change to be handled. + */ + /* + This is done last because it also control the + status of umsdos_isinit() + */ + Printk (("umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%d)\n", inode, dir, f_pos)); + umsdos_set_dirinfo (inode,dir,f_pos); + } + }else if (dir != NULL){ + /* + Test to see if the info is maintained. + This should be removed when the file system will be proven. + */ + /* FIXME, again, not a clue */ + struct inode *emd_owner; + Printk (("umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n")); + emd_owner = umsdos_emd_dir_lookup(dir,1); + iput (emd_owner); + if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){ + printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld " + ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner); + } + } } + + /* - Get the inode of the directory which owns this inode. - Return 0 if ok, -EIO if error. + Get the inode of the directory which owns this inode. + Return 0 if ok, -EIO if error. */ int umsdos_get_dirowner( struct inode *inode, @@ -217,14 +251,17 @@ } return ret; } + + + /* Load an inode from disk. */ void UMSDOS_read_inode(struct inode *inode) { - PRINTK (("read inode %x ino = %d ",inode,inode->i_ino)); + Printk (("UMSDOS_read_inode %x ino = %d ",inode,inode->i_ino)); msdos_read_inode(inode); - PRINTK (("ino = %d %d\n",inode->i_ino,atomic_read(&inode->i_count))); + PRINTK (("ino after msdos_read_inode= %d\n",inode->i_ino)); if (S_ISDIR(inode->i_mode) && (inode->u.umsdos_i.u.dir_info.creating != 0 || inode->u.umsdos_i.u.dir_info.looking != 0 @@ -250,6 +287,7 @@ umsdos_patch_inode(inode,NULL,0); } + /* Update the disk with the inode content */ @@ -257,7 +295,7 @@ { struct iattr newattrs; - PRINTK (("UMSDOS_write_inode emd %d\n",inode->u.umsdos_i.i_emd_owner)); + PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",inode->u.umsdos_i.i_emd_owner)); fat_write_inode(inode); newattrs.ia_mtime = inode->i_mtime; newattrs.ia_atime = inode->i_atime; @@ -268,244 +306,288 @@ to update the EMD entry associated with this inode. But it has the side effect to re"dirt" the inode. */ + /* FIXME, notify_change now takes a dentry, not an + inode so, the emd update needs to be done here UMSDOS_notify_change (inode, &newattrs); - inode->i_dirt = 0; + */ + + /* FIXME inode->i_dirt = 0; */ } -int UMSDOS_notify_change(struct inode *inode, struct iattr *attr) +int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) { - int ret = 0; - - if ((ret = inode_change_ok(inode, attr)) != 0) - return ret; - - if (inode->i_nlink > 0){ - /* #Specification: notify_change / i_nlink > 0 - notify change is only done for inode with nlink > 0. An inode - with nlink == 0 is no longer associated with any entry in - the EMD file, so there is nothing to update. - */ - unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner; - if (inode == inode->i_sb->s_mounted){ - /* #Specification: root inode / attributes - I don't know yet how this should work. Normally - the attributes (permissions bits, owner, times) of - a directory are stored in the EMD file of its parent. - - One thing we could do is store the attributes of the root - inode in its own EMD file. A simple entry named "." could - be used for this special case. It would be read once - when the file system is mounted and update in - UMSDOS_notify_change() (right here). - - I am not sure of the behavior of the root inode for - a real UNIX file system. For now, this is a nop. - */ - }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){ - /* This inode is not a EMD file nor an inode used internally - by MSDOS, so we can update its status. - See emd.c - */ - struct inode *emd_owner = iget (inode->i_sb,i_emd_owner); - PRINTK (("notify change %p ",inode)); - if (emd_owner == NULL){ - printk ("UMSDOS: emd_owner = NULL ???"); - ret = -EPERM; - }else{ - struct file filp; - struct umsdos_dirent entry; - filp.f_pos = inode->u.umsdos_i.pos; - filp.f_reada = 0; - PRINTK (("pos = %d ",filp.f_pos)); - /* Read only the start of the entry since we don't touch */ - /* the name */ - ret = umsdos_emd_dir_read (emd_owner,&filp,(char*)&entry - ,UMSDOS_REC_SIZE); - if (ret == 0){ - if (attr->ia_valid & ATTR_UID) - entry.uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - entry.gid = attr->ia_gid; - if (attr->ia_valid & ATTR_MODE) - entry.mode = attr->ia_mode; - if (attr->ia_valid & ATTR_ATIME) - entry.atime = attr->ia_atime; - if (attr->ia_valid & ATTR_MTIME) - entry.mtime = attr->ia_mtime; - if (attr->ia_valid & ATTR_CTIME) - entry.ctime = attr->ia_ctime; - - entry.nlink = inode->i_nlink; - filp.f_pos = inode->u.umsdos_i.pos; - ret = umsdos_emd_dir_write (emd_owner,&filp,(char*)&entry - ,UMSDOS_REC_SIZE); - - PRINTK (("notify pos %d ret %d nlink %d " - ,inode->u.umsdos_i.pos - ,ret,entry.nlink)); - /* #Specification: notify_change / msdos fs - notify_change operation are done only on the - EMD file. The msdos fs is not even called. - */ - } - iput (emd_owner); - } - PRINTK (("\n")); - } + int ret = 0; + struct inode *inode = dentry->d_inode; + + Printk (("UMSDOS_notify_change: /mn/ completly untested\n")); + + if ((ret = inode_change_ok(inode, attr)) != 0) + return ret; + + if (inode->i_nlink > 0){ + /* #Specification: notify_change / i_nlink > 0 + notify change is only done for inode with nlink > 0. An inode + with nlink == 0 is no longer associated with any entry in + the EMD file, so there is nothing to update. + */ + unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner; + if (inode == iget(inode->i_sb,UMSDOS_ROOT_INO)){ + /* #Specification: root inode / attributes + I don't know yet how this should work. Normally + the attributes (permissions bits, owner, times) of + a directory are stored in the EMD file of its parent. + + One thing we could do is store the attributes of the root + inode in its own EMD file. A simple entry named "." could + be used for this special case. It would be read once + when the file system is mounted and update in + UMSDOS_notify_change() (right here). + + I am not sure of the behavior of the root inode for + a real UNIX file system. For now, this is a nop. + */ + }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){ + /* This inode is not a EMD file nor an inode used internally + by MSDOS, so we can update its status. + See emd.c + */ + struct inode *emd_owner = iget (inode->i_sb,i_emd_owner); + Printk (("notify change %p ",inode)); + if (emd_owner == NULL){ + printk ("UMSDOS: emd_owner = NULL ???"); + ret = -EPERM; + }else{ + struct file filp; + struct umsdos_dirent entry; + loff_t offs; + offs = 0; + filp.f_pos = inode->u.umsdos_i.pos; + filp.f_reada = 0; + Printk (("pos = %d ",filp.f_pos)); + /* Read only the start of the entry since we don't touch */ + /* the name */ + ret = umsdos_emd_dir_read (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); + if (ret == 0){ + if (attr->ia_valid & ATTR_UID) + entry.uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + entry.gid = attr->ia_gid; + if (attr->ia_valid & ATTR_MODE) + entry.mode = attr->ia_mode; + if (attr->ia_valid & ATTR_ATIME) + entry.atime = attr->ia_atime; + if (attr->ia_valid & ATTR_MTIME) + entry.mtime = attr->ia_mtime; + if (attr->ia_valid & ATTR_CTIME) + entry.ctime = attr->ia_ctime; + + entry.nlink = inode->i_nlink; + filp.f_pos = inode->u.umsdos_i.pos; + offs = 0; /* FIXME */ + ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); + + Printk (("notify pos %d ret %d nlink %d " + ,inode->u.umsdos_i.pos + ,ret,entry.nlink)); + /* #Specification: notify_change / msdos fs + notify_change operation are done only on the + EMD file. The msdos fs is not even called. + */ } - if (ret == 0) - inode_setattr(inode, attr); - return ret; + iput (emd_owner); + } + Printk (("\n")); + } + } + if (ret == 0) + inode_setattr(inode, attr); + return ret; } /* #Specification: function name / convention - A simple convention for function name has been used in - the UMSDOS file system. First all function use the prefix - umsdos_ to avoid name clash with other part of the kernel. - - And standard VFS entry point use the prefix UMSDOS (upper case) - so it's easier to tell them apart. + A simple convention for function name has been used in + the UMSDOS file system. First all function use the prefix + umsdos_ to avoid name clash with other part of the kernel. + + And standard VFS entry point use the prefix UMSDOS (upper case) + so it's easier to tell them apart. + N.B. (FIXME) PTW, the order and contents of this struct changed */ static struct super_operations umsdos_sops = { - UMSDOS_read_inode, - UMSDOS_notify_change, - UMSDOS_write_inode, - UMSDOS_put_inode, - UMSDOS_put_super, - NULL, /* added in 0.96c */ - UMSDOS_statfs, - NULL + UMSDOS_read_inode, /* read_inode */ + UMSDOS_write_inode, /* write_inode */ + UMSDOS_put_inode, /* put_inode */ + NULL, /* delete_inode */ + UMSDOS_notify_change, /* notify_change */ + UMSDOS_put_super, /* put_super */ + NULL, /* write_super */ + fat_statfs, /* statfs */ + NULL /* remount_fs*/ }; /* - Read the super block of an Extended MS-DOS FS. + Read the super block of an Extended MS-DOS FS. */ struct super_block *UMSDOS_read_super( - struct super_block *s, - void *data, - int silent) -{ - /* #Specification: mount / options - Umsdos run on top of msdos. Currently, it supports no - mount option, but happily pass all option received to - the msdos driver. I am not sure if all msdos mount option - make sense with Umsdos. Here are at least those who - are useful. - uid= - gid= - - These options affect the operation of umsdos in directories - which do not have an EMD file. They behave like normal - msdos directory, with all limitation of msdos. - */ - struct super_block *sb; - MOD_INC_USE_COUNT; - sb = msdos_read_super(s,data,silent); - printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n" - ,UMSDOS_VERSION,UMSDOS_RELEASE); - if (sb != NULL){ - MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */ - sb->s_op = &umsdos_sops; - PRINTK (("umsdos_read_super %p\n",sb->s_mounted)); - umsdos_setup_dir_inode (sb->s_mounted); - PRINTK (("End umsdos_read_super\n")); - if (s == super_blocks){ - /* #Specification: pseudo root / mount - When a umsdos fs is mounted, a special handling is done - if it is the root partition. We check for the presence - of the file /linux/etc/init or /linux/etc/rc or - /linux/sbin/init. If one is there, we do a chroot("/linux"). - - We check both because (see init/main.c) the kernel - try to exec init at different place and if it fails - it tries /bin/sh /etc/rc. To be consistent with - init/main.c, many more test would have to be done - to locate init. Any complain ? - - The chroot is done manually in init/main.c but the - info (the inode) is located at mount time and store - in a global variable (pseudo_root) which is used at - different place in the umsdos driver. There is no - need to store this variable elsewhere because it - will always be one, not one per mount. - - This feature allows the installation - of a linux system within a DOS system in a subdirectory. - - A user may install its linux stuff in c:\linux - avoiding any clash with existing DOS file and subdirectory. - When linux boots, it hides this fact, showing a normal - root directory with /etc /bin /tmp ... - - The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h - in the macro UMSDOS_PSDROOT_NAME. - */ - - struct inode *pseudo; - Printk (("Mounting root\n")); - if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME - ,UMSDOS_PSDROOT_LEN,&pseudo)==0 - && S_ISDIR(pseudo->i_mode)){ - struct inode *etc = NULL; - struct inode *sbin = NULL; - int pseudo_ok = 0; - Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME)); - if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0 - && S_ISDIR(etc->i_mode)){ - struct inode *init = NULL; - struct inode *rc = NULL; - Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); - if ((umsdos_real_lookup (etc,"init",4,&init)==0 - && S_ISREG(init->i_mode)) - || (umsdos_real_lookup (etc,"rc",2,&rc)==0 - && S_ISREG(rc->i_mode))){ - pseudo_ok = 1; - } - iput (init); - iput (rc); - } - if (!pseudo_ok - && umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0 - && S_ISDIR(sbin->i_mode)){ - struct inode *init = NULL; - Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME)); - if (umsdos_real_lookup (sbin,"init",4,&init)==0 - && S_ISREG(init->i_mode)){ - pseudo_ok = 1; - } - iput (init); - } - if (pseudo_ok){ - umsdos_setup_dir_inode (pseudo); - Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); - pseudo_root = pseudo; - atomic_inc(&pseudo->i_count); - pseudo = NULL; - } - iput (sbin); - iput (etc); - } - iput (pseudo); - } - } else { - MOD_DEC_USE_COUNT; + struct super_block *sb, + void *data, + int silent) +{ + /* #Specification: mount / options + Umsdos run on top of msdos. Currently, it supports no + mount option, but happily pass all option received to + the msdos driver. I am not sure if all msdos mount option + make sense with Umsdos. Here are at least those who + are useful. + uid= + gid= + + These options affect the operation of umsdos in directories + which do not have an EMD file. They behave like normal + msdos directory, with all limitation of msdos. + */ + struct super_block *res; + struct inode *pseudo=NULL; + Printk (("UMSDOS /mn/: starting UMSDOS_read_super\n")); + MOD_INC_USE_COUNT; + Printk (("UMSDOS /mn/: sb = %p\n",sb)); + res = msdos_read_super(sb,data,silent); + Printk (("UMSDOS /mn/: res = %p\n",res)); + printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); + + if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; } + + MSDOS_SB(res)->options.dotsOK = 0; /* disable hidden==dotfile */ + res->s_op = &umsdos_sops; + Printk (("umsdos /mn/: here goes the iget ROOT_INO\n")); + + pseudo = iget(res,UMSDOS_ROOT_INO); + Printk (("umsdos_read_super %p\n",pseudo)); + + umsdos_setup_dir_inode (pseudo); + +#if 0 /* disabled /mn/ test FIXME */ + + /* if (s == super_blocks){ FIXME, super_blocks no longer exported */ + if(pseudo) { + /* #Specification: pseudo root / mount + When a umsdos fs is mounted, a special handling is done + if it is the root partition. We check for the presence + of the file /linux/etc/init or /linux/etc/rc or + /linux/sbin/init. If one is there, we do a chroot("/linux"). + + We check both because (see init/main.c) the kernel + try to exec init at different place and if it fails + it tries /bin/sh /etc/rc. To be consistent with + init/main.c, many more test would have to be done + to locate init. Any complain ? + + The chroot is done manually in init/main.c but the + info (the inode) is located at mount time and store + in a global variable (pseudo_root) which is used at + different place in the umsdos driver. There is no + need to store this variable elsewhere because it + will always be one, not one per mount. + + This feature allows the installation + of a linux system within a DOS system in a subdirectory. + + A user may install its linux stuff in c:\linux + avoiding any clash with existing DOS file and subdirectory. + When linux boots, it hides this fact, showing a normal + root directory with /etc /bin /tmp ... + + The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h + in the macro UMSDOS_PSDROOT_NAME. + */ + struct dentry *root, *etc, *etc_rc, *init, *sbin; /* FIXME */ + + root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL); + sbin = creat_dentry ("sbin", 4, NULL); + + Printk (("Mounting root\n")); + if (umsdos_real_lookup (pseudo,root)==0 + && (root->d_inode != NULL) + && S_ISDIR(root->d_inode->i_mode)){ + + int pseudo_ok = 0; + Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME)); + etc = creat_dentry ("etc", 3, NULL); + + + /* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */ + if(umsdos_real_lookup(pseudo, etc) == 0 + && S_ISDIR(etc->d_inode->i_mode)){ + + Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); + + init = creat_dentry ("init", 4, NULL); + etc_rc = creat_dentry ("rc", 2, NULL); + + /* if ((umsdos_real_lookup (etc,"init",4,init)==0*/ + if((umsdos_real_lookup(pseudo, init) == 0 + && S_ISREG(init->d_inode->i_mode)) + /* || (umsdos_real_lookup (etc,"rc",2,&rc)==0*/ + || (umsdos_real_lookup(pseudo, etc_rc) == 0 + && S_ISREG(etc_rc->d_inode->i_mode))){ + pseudo_ok = 1; + } + /* FIXME !!!!!! */ + /* iput(init); */ + /* iput(rc); */ } - return sb; + if (!pseudo_ok + /* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0*/ + && umsdos_real_lookup(pseudo, sbin) == 0 + && S_ISDIR(sbin->d_inode->i_mode)){ + + Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME)); + /* if (umsdos_real_lookup (sbin,"init",4,init)==0 */ + if(umsdos_real_lookup(pseudo, init) == 0 + && S_ISREG(init->d_inode->i_mode)){ + pseudo_ok = 1; + } + /* FIXME !!! + iput (init); */ + } + if (pseudo_ok){ + umsdos_setup_dir_inode (pseudo); + Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); + pseudo_root = pseudo; + pseudo->i_count++; + pseudo = NULL; + } + /* FIXME + + iput (sbin); + iput (etc); + */ + } + + Printk (("umsdos_read_super /mn/: Pseudo should be iput-ed here...\n")); + + iput (pseudo); /* FIXME */ + } + +#endif /* disabled */ + + Printk (("umsdos_read_super /mn/: returning %p\n",res)); + return res; } static struct file_system_type umsdos_fs_type = { - "umsdos", - FS_REQUIRES_DEV, - UMSDOS_read_super, - NULL + "umsdos", + FS_REQUIRES_DEV, + UMSDOS_read_super, + NULL }; __initfunc(int init_umsdos_fs(void)) { - return register_filesystem(&umsdos_fs_type); + return register_filesystem(&umsdos_fs_type); } #ifdef MODULE @@ -513,12 +595,12 @@ int init_module(void) { - return init_umsdos_fs(); + return init_umsdos_fs(); } void cleanup_module(void) { - unregister_filesystem(&umsdos_fs_type); + unregister_filesystem(&umsdos_fs_type); } #endif diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v2.1.86/linux/fs/umsdos/ioctl.c Mon Jun 16 16:35:59 1997 +++ linux/fs/umsdos/ioctl.c Thu Feb 12 13:36:57 1998 @@ -34,18 +34,18 @@ off_t offset, ino_t ino) { - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; - if (d->count == 0){ - copy_to_user (d->ent->d_name,name,name_len); - put_user ('\0',d->ent->d_name+name_len); - put_user (name_len,&d->ent->d_reclen); - put_user (ino,&d->ent->d_ino); - put_user (offset,&d->ent->d_off); - d->count = 1; - ret = 0; - } - return ret; + int ret = -EINVAL; + struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; + if (d->count == 0){ + copy_to_user (d->ent->d_name,name,name_len); + put_user ('\0',d->ent->d_name+name_len); + put_user (name_len,&d->ent->d_reclen); + put_user (ino,&d->ent->d_ino); + put_user (offset,&d->ent->d_off); + d->count = 1; + ret = 0; + } + return ret; } @@ -53,266 +53,281 @@ Perform special function on a directory */ int UMSDOS_ioctl_dir ( - struct inode *dir, - struct file *filp, - unsigned int cmd, - unsigned long data) + struct inode *dir, + struct file *filp, + unsigned int cmd, + unsigned long data) { - int ret = -EPERM; - int err; - /* #Specification: ioctl / acces - Only root (effective id) is allowed to do IOCTL on directory - in UMSDOS. EPERM is returned for other user. + int ret = -EPERM; + int err; + /* #Specification: ioctl / acces + Only root (effective id) is allowed to do IOCTL on directory + in UMSDOS. EPERM is returned for other user. + */ + /* + Well, not all cases require write access, but it simplifies + the code, and let's face it, there is only one client (umssync) + for all this. + */ + if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) { + ret = err; + }else if (current->euid == 0 + || cmd == UMSDOS_GETVERSION){ + struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data; + ret = -EINVAL; + /* #Specification: ioctl / prototypes + The official prototype for the umsdos ioctl on directory + is: + + int ioctl ( + int fd, // File handle of the directory + int cmd, // command + struct umsdos_ioctl *data) + + The struct and the commands are defined in linux/umsdos_fs.h. + + umsdos_progs/umsdosio.c provide an interface in C++ to all + these ioctl. umsdos_progs/udosctl is a small utility showing + all this. + + These ioctl generally allow one to work on the EMD or the + DOS directory independently. These are essential to implement + the synchronise. + */ + Printk (("ioctl %d ",cmd)); + if (cmd == UMSDOS_GETVERSION){ + /* #Specification: ioctl / UMSDOS_GETVERSION + The field version and release of the structure + umsdos_ioctl are filled with the version and release + number of the fs code in the kernel. This will allow + some form of checking. Users won't be able to run + incompatible utility such as the synchroniser (umssync). + umsdos_progs/umsdosio.c enforce this checking. + + Return always 0. + */ + put_user(UMSDOS_VERSION,&idata->version); + put_user(UMSDOS_RELEASE,&idata->release); + ret = 0; + }else if (cmd == UMSDOS_READDIR_DOS){ + /* #Specification: ioctl / UMSDOS_READDIR_DOS + One entry is read from the DOS directory at the current + file position. The entry is put as is in the dos_dirent + field of struct umsdos_ioctl. + + Return > 0 if success. + */ + struct UMSDOS_DIR_ONCE bufk; + bufk.count = 0; + bufk.ent = &idata->dos_dirent; + + fat_readdir(filp,&bufk,umsdos_ioctl_fill); + + ret = bufk.count == 1 ? 1 : 0; + }else if (cmd == UMSDOS_READDIR_EMD){ + /* #Specification: ioctl / UMSDOS_READDIR_EMD + One entry is read from the EMD at the current + file position. The entry is put as is in the umsdos_dirent + field of struct umsdos_ioctl. The corresponding mangled + DOS entry name is put in the dos_dirent field. + + All entries are read including hidden links. Blank + entries are skipped. + + Return > 0 if success. + */ + struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0); + if (emd_dir != NULL){ + while (1){ + if (filp->f_pos >= emd_dir->i_size){ + ret = 0; + break; + }else{ + struct umsdos_dirent entry; + off_t f_pos = filp->f_pos; + ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry); + if (ret < 0){ + break; + }else if (entry.name_len > 0){ + struct umsdos_info info; + ret = entry.name_len; + umsdos_parse (entry.name,entry.name_len,&info); + info.f_pos = f_pos; + umsdos_manglename(&info); + copy_to_user(&idata->umsdos_dirent,&entry + ,sizeof(entry)); + copy_to_user(&idata->dos_dirent.d_name + ,info.fake.fname,info.fake.len+1); + break; + } + } + } + iput (emd_dir); + }else{ + /* The absence of the EMD is simply seen as an EOF */ + ret = 0; + } + }else if (cmd == UMSDOS_INIT_EMD){ + /* #Specification: ioctl / UMSDOS_INIT_EMD + The UMSDOS_INIT_EMD command make sure the EMD + exist for a directory. If it does not, it is + created. Also, it makes sure the directory functions + table (struct inode_operations) is set to the UMSDOS + semantic. This mean that umssync may be applied to + an "opened" msdos directory, and it will change behavior + on the fly. + + Return 0 if success. + */ + extern struct inode_operations umsdos_rdir_inode_operations; + struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1); + ret = emd_dir != NULL; + iput (emd_dir); + + dir->i_op = ret + ? &umsdos_dir_inode_operations + : &umsdos_rdir_inode_operations; + }else{ + struct umsdos_ioctl data; + copy_from_user (&data,idata,sizeof(data)); + if (cmd == UMSDOS_CREAT_EMD){ + /* #Specification: ioctl / UMSDOS_CREAT_EMD + The umsdos_dirent field of the struct umsdos_ioctl is used + as is to create a new entry in the EMD of the directory. + The DOS directory is not modified. + No validation is done (yet). + + Return 0 if success. + */ + struct umsdos_info info; + /* This makes sure info.entry and info in general is correctly */ + /* initialised */ + memcpy (&info.entry,&data.umsdos_dirent + ,sizeof(data.umsdos_dirent)); + umsdos_parse (data.umsdos_dirent.name + ,data.umsdos_dirent.name_len,&info); + ret = umsdos_newentry (dir,&info); + }else if (cmd == UMSDOS_RENAME_DOS){ + struct dentry *old_dentry,*new_dentry; /* FIXME */ + /* #Specification: ioctl / UMSDOS_RENAME_DOS + A file or directory is rename in a DOS directory + (not moved across directory). The source name + is in the dos_dirent.name field and the destination + is in umsdos_dirent.name field. + + This ioctl allows umssync to rename a mangle file + name before syncing it back in the EMD. */ + dir->i_count+=2; /* - Well, not all cases require write access, but it simplifies - the code, and let's face it, there is only one client (umssync) - for all this. + ret = msdos_rename (dir + ,data.dos_dirent.d_name,data.dos_dirent.d_reclen + ,dir + ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); */ - if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) { - ret = err; - }else if (current->euid == 0 - || cmd == UMSDOS_GETVERSION){ - struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data; - ret = -EINVAL; - /* #Specification: ioctl / prototypes - The official prototype for the umsdos ioctl on directory - is: - - int ioctl ( - int fd, // File handle of the directory - int cmd, // command - struct umsdos_ioctl *data) - - The struct and the commands are defined in linux/umsdos_fs.h. - - umsdos_progs/umsdosio.c provide an interface in C++ to all - these ioctl. umsdos_progs/udosctl is a small utility showing - all this. - - These ioctl generally allow one to work on the EMD or the - DOS directory independently. These are essential to implement - the synchronise. - */ - PRINTK (("ioctl %d ",cmd)); - if (cmd == UMSDOS_GETVERSION){ - /* #Specification: ioctl / UMSDOS_GETVERSION - The field version and release of the structure - umsdos_ioctl are filled with the version and release - number of the fs code in the kernel. This will allow - some form of checking. Users won't be able to run - incompatible utility such as the synchroniser (umssync). - umsdos_progs/umsdosio.c enforce this checking. - - Return always 0. - */ - put_user(UMSDOS_VERSION,&idata->version); - put_user(UMSDOS_RELEASE,&idata->release); - ret = 0; - }else if (cmd == UMSDOS_READDIR_DOS){ - /* #Specification: ioctl / UMSDOS_READDIR_DOS - One entry is read from the DOS directory at the current - file position. The entry is put as is in the dos_dirent - field of struct umsdos_ioctl. - - Return > 0 if success. - */ - struct UMSDOS_DIR_ONCE bufk; - bufk.count = 0; - bufk.ent = &idata->dos_dirent; - fat_readdir(dir,filp,&bufk,umsdos_ioctl_fill); - ret = bufk.count == 1 ? 1 : 0; - }else if (cmd == UMSDOS_READDIR_EMD){ - /* #Specification: ioctl / UMSDOS_READDIR_EMD - One entry is read from the EMD at the current - file position. The entry is put as is in the umsdos_dirent - field of struct umsdos_ioctl. The corresponding mangled - DOS entry name is put in the dos_dirent field. - - All entries are read including hidden links. Blank - entries are skipped. - - Return > 0 if success. - */ - struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0); - if (emd_dir != NULL){ - while (1){ - if (filp->f_pos >= emd_dir->i_size){ - ret = 0; - break; - }else{ - struct umsdos_dirent entry; - off_t f_pos = filp->f_pos; - ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry); - if (ret < 0){ - break; - }else if (entry.name_len > 0){ - struct umsdos_info info; - ret = entry.name_len; - umsdos_parse (entry.name,entry.name_len,&info); - info.f_pos = f_pos; - umsdos_manglename(&info); - copy_to_user(&idata->umsdos_dirent,&entry - ,sizeof(entry)); - copy_to_user(&idata->dos_dirent.d_name - ,info.fake.fname,info.fake.len+1); - break; - } - } - } - iput (emd_dir); - }else{ - /* The absence of the EMD is simply seen as an EOF */ - ret = 0; - } - }else if (cmd == UMSDOS_INIT_EMD){ - /* #Specification: ioctl / UMSDOS_INIT_EMD - The UMSDOS_INIT_EMD command make sure the EMD - exist for a directory. If it does not, it is - created. Also, it makes sure the directory functions - table (struct inode_operations) is set to the UMSDOS - semantic. This mean that umssync may be applied to - an "opened" msdos directory, and it will change behavior - on the fly. - - Return 0 if success. - */ - extern struct inode_operations umsdos_rdir_inode_operations; - struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1); - ret = emd_dir != NULL; - iput (emd_dir); - - dir->i_op = ret - ? &umsdos_dir_inode_operations - : &umsdos_rdir_inode_operations; - }else{ - struct umsdos_ioctl data; - copy_from_user (&data,idata,sizeof(data)); - if (cmd == UMSDOS_CREAT_EMD){ - /* #Specification: ioctl / UMSDOS_CREAT_EMD - The umsdos_dirent field of the struct umsdos_ioctl is used - as is to create a new entry in the EMD of the directory. - The DOS directory is not modified. - No validation is done (yet). - - Return 0 if success. - */ - struct umsdos_info info; - /* This makes sure info.entry and info in general is correctly */ - /* initialised */ - memcpy (&info.entry,&data.umsdos_dirent - ,sizeof(data.umsdos_dirent)); - umsdos_parse (data.umsdos_dirent.name - ,data.umsdos_dirent.name_len,&info); - ret = umsdos_newentry (dir,&info); - }else if (cmd == UMSDOS_RENAME_DOS){ - /* #Specification: ioctl / UMSDOS_RENAME_DOS - A file or directory is rename in a DOS directory - (not moved across directory). The source name - is in the dos_dirent.name field and the destination - is in umsdos_dirent.name field. - - This ioctl allows umssync to rename a mangle file - name before syncing it back in the EMD. - */ - atomic_add(2, &dir->i_count); - ret = msdos_rename (dir - ,data.dos_dirent.d_name,data.dos_dirent.d_reclen - ,dir - ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); - }else if (cmd == UMSDOS_UNLINK_EMD){ - /* #Specification: ioctl / UMSDOS_UNLINK_EMD - The umsdos_dirent field of the struct umsdos_ioctl is used - as is to remove an entry from the EMD of the directory. - No validation is done (yet). The mode field is used - to validate S_ISDIR or S_ISREG. - - Return 0 if success. - */ - struct umsdos_info info; - /* This makes sure info.entry and info in general is correctly */ - /* initialised */ - memcpy (&info.entry,&data.umsdos_dirent - ,sizeof(data.umsdos_dirent)); - umsdos_parse (data.umsdos_dirent.name - ,data.umsdos_dirent.name_len,&info); - ret = umsdos_delentry (dir,&info - ,S_ISDIR(data.umsdos_dirent.mode)); - }else if (cmd == UMSDOS_UNLINK_DOS){ - /* #Specification: ioctl / UMSDOS_UNLINK_DOS - The dos_dirent field of the struct umsdos_ioctl is used to - execute a msdos_unlink operation. The d_name and d_reclen - fields are used. - - Return 0 if success. - */ - atomic_inc(&dir->i_count); - ret = msdos_unlink (dir,data.dos_dirent.d_name - ,data.dos_dirent.d_reclen); - }else if (cmd == UMSDOS_RMDIR_DOS){ - /* #Specification: ioctl / UMSDOS_RMDIR_DOS - The dos_dirent field of the struct umsdos_ioctl is used to - execute a msdos_unlink operation. The d_name and d_reclen - fields are used. - - Return 0 if success. - */ - atomic_inc(&dir->i_count); - ret = msdos_rmdir (dir,data.dos_dirent.d_name - ,data.dos_dirent.d_reclen); - }else if (cmd == UMSDOS_STAT_DOS){ - /* #Specification: ioctl / UMSDOS_STAT_DOS - The dos_dirent field of the struct umsdos_ioctl is - used to execute a stat operation in the DOS directory. - The d_name and d_reclen fields are used. - - The following field of umsdos_ioctl.stat are filled. - - st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, - Return 0 if success. - */ - struct inode *inode; - ret = umsdos_real_lookup (dir,data.dos_dirent.d_name - ,data.dos_dirent.d_reclen,&inode); - if (ret == 0){ - data.stat.st_ino = inode->i_ino; - data.stat.st_mode = inode->i_mode; - data.stat.st_size = inode->i_size; - data.stat.st_atime = inode->i_atime; - data.stat.st_ctime = inode->i_ctime; - data.stat.st_mtime = inode->i_mtime; - copy_to_user (&idata->stat,&data.stat,sizeof(data.stat)); - iput (inode); - } - }else if (cmd == UMSDOS_DOS_SETUP){ - /* #Specification: ioctl / UMSDOS_DOS_SETUP - The UMSDOS_DOS_SETUP ioctl allow changing the - default permission of the MsDOS file system driver - on the fly. The MsDOS driver apply global permission - to every file and directory. Normally these permissions - are controlled by a mount option. This is not - available for root partition, so a special utility - (umssetup) is provided to do this, normally in - /etc/rc.local. - - Be aware that this apply ONLY to MsDOS directory - (those without EMD --linux-.---). Umsdos directory - have independent (standard) permission for each - and every file. - - The field umsdos_dirent provide the information needed. - umsdos_dirent.uid and gid sets the owner and group. - umsdos_dirent.mode set the permissions flags. - */ - dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid; - dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid; - dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode; - ret = 0; - } - } + old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL); + new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL); + ret = msdos_rename(dir,old_dentry,dir,new_dentry); + }else if (cmd == UMSDOS_UNLINK_EMD){ + /* #Specification: ioctl / UMSDOS_UNLINK_EMD + The umsdos_dirent field of the struct umsdos_ioctl is used + as is to remove an entry from the EMD of the directory. + No validation is done (yet). The mode field is used + to validate S_ISDIR or S_ISREG. + + Return 0 if success. + */ + struct umsdos_info info; + /* This makes sure info.entry and info in general is correctly */ + /* initialised */ + memcpy (&info.entry,&data.umsdos_dirent + ,sizeof(data.umsdos_dirent)); + umsdos_parse (data.umsdos_dirent.name + ,data.umsdos_dirent.name_len,&info); + ret = umsdos_delentry (dir,&info + ,S_ISDIR(data.umsdos_dirent.mode)); + }else if (cmd == UMSDOS_UNLINK_DOS){ + struct dentry *dentry; /* FIXME */ + /* #Specification: ioctl / UMSDOS_UNLINK_DOS + The dos_dirent field of the struct umsdos_ioctl is used to + execute a msdos_unlink operation. The d_name and d_reclen + fields are used. + + Return 0 if success. + */ + dir->i_count++; + /* + ret = msdos_unlink (dir,data.dos_dirent.d_name,data.dos_dirent.d_reclen); + */ + ret = msdos_unlink(dir,dentry); + }else if (cmd == UMSDOS_RMDIR_DOS){ + struct dentry *dentry; /* FIXME */ + /* #Specification: ioctl / UMSDOS_RMDIR_DOS + The dos_dirent field of the struct umsdos_ioctl is used to + execute a msdos_unlink operation. The d_name and d_reclen + fields are used. + + Return 0 if success. + */ + dir->i_count++; + /* + ret = msdos_rmdir (dir,data.dos_dirent.d_name + ,data.dos_dirent.d_reclen); + */ + ret = msdos_rmdir(dir,dentry); + }else if (cmd == UMSDOS_STAT_DOS){ + /* #Specification: ioctl / UMSDOS_STAT_DOS + The dos_dirent field of the struct umsdos_ioctl is + used to execute a stat operation in the DOS directory. + The d_name and d_reclen fields are used. + + The following field of umsdos_ioctl.stat are filled. + + st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, + Return 0 if success. + */ + struct inode *inode; + + ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode); + if (ret == 0){ + data.stat.st_ino = inode->i_ino; + data.stat.st_mode = inode->i_mode; + data.stat.st_size = inode->i_size; + data.stat.st_atime = inode->i_atime; + data.stat.st_ctime = inode->i_ctime; + data.stat.st_mtime = inode->i_mtime; + copy_to_user (&idata->stat,&data.stat,sizeof(data.stat)); + iput (inode); } - PRINTK (("ioctl return %d\n",ret)); - return ret; + }else if (cmd == UMSDOS_DOS_SETUP){ + /* #Specification: ioctl / UMSDOS_DOS_SETUP + The UMSDOS_DOS_SETUP ioctl allow changing the + default permission of the MsDOS file system driver + on the fly. The MsDOS driver apply global permission + to every file and directory. Normally these permissions + are controlled by a mount option. This is not + available for root partition, so a special utility + (umssetup) is provided to do this, normally in + /etc/rc.local. + + Be aware that this apply ONLY to MsDOS directory + (those without EMD --linux-.---). Umsdos directory + have independent (standard) permission for each + and every file. + + The field umsdos_dirent provide the information needed. + umsdos_dirent.uid and gid sets the owner and group. + umsdos_dirent.mode set the permissions flags. + */ + dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid; + dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid; + dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode; + ret = 0; + } + } + } + Printk (("ioctl return %d\n",ret)); + return ret; } diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/mangle.c linux/fs/umsdos/mangle.c --- v2.1.86/linux/fs/umsdos/mangle.c Sun Feb 25 01:17:59 1996 +++ linux/fs/umsdos/mangle.c Thu Feb 12 13:36:57 1998 @@ -13,472 +13,474 @@ #include /* - Complete the mangling of the MSDOS fake name - based on the position of the entry in the EMD file. + Complete the mangling of the MSDOS fake name + based on the position of the entry in the EMD file. - Simply complete the job of umsdos_parse; fill the extension. + Simply complete the job of umsdos_parse; fill the extension. - Beware that info->f_pos must be set. + Beware that info->f_pos must be set. */ void umsdos_manglename (struct umsdos_info *info) { - if (info->msdos_reject){ - /* #Specification: file name / non MSDOS conforming / mangling - Each non MSDOS conforming file has a special extension - build from the entry position in the EMD file. - - This number is then transform in a base 32 number, where - each digit is expressed like hexadecimal number, using - digit and letter, except it uses 22 letters from 'a' to 'v'. - The number 32 comes from 2**5. It is faster to split a binary - number using a base which is a power of two. And I was 32 - when I started this project. Pick your answer :-) . - - If the result is '0', it is replace with '_', simply - to make it odd. - - This is true for the first two character of the extension. - The last one is taken from a list of odd character, which - are: - - { } ( ) ! ` ^ & @ - - With this scheme, we can produce 9216 ( 9* 32 * 32) - different extensions which should not clash with any useful - extension already popular or meaningful. Since most directory - have much less than 32 * 32 files in it, the first character - of the extension of any mangle name will be {. - - Here are the reason to do this (this kind of mangling). - - -The mangling is deterministic. Just by the extension, we - are able to locate the entry in the EMD file. - - -By keeping to beginning of the file name almost unchanged, - we are helping the MSDOS user. - - -The mangling produces names not too ugly, so an msdos user - may live with it (remember it, type it, etc...). - - -The mangling produces names ugly enough so no one will - ever think of using such a name in real life. This is not - fool proof. I don't think there is a total solution to this. - */ - union { - int entry_num; - struct { - unsigned num1:5,num2:5,num3:5; - }num; - } u; - char *pt = info->fake.fname + info->fake.len; - /* lookup for encoding the last character of the extension */ - /* It contain valid character after the ugly one to make sure */ - /* even if someone overflow the 32 * 32 * 9 limit, it still do */ - /* something */ - #define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@' - static char lookup3[]={ - SPECIAL_MANGLING, - /* This is the start of lookup12 */ - '_','1','2','3','4','5','6','7','8','9', - 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', - 'p','q','r','s','t','u','v' - }; - #define lookup12 (lookup3+9) - u.entry_num = info->f_pos / UMSDOS_REC_SIZE; - if (u.entry_num > (9* 32 * 32)){ - printk ("UMSDOS: More than 9216 file in a directory.\n" - "This may break the mangling strategy.\n" - "Not a killer problem. See doc.\n"); - } - *pt++ = '.'; - *pt++ = lookup3 [u.num.num3]; - *pt++ = lookup12[u.num.num2]; - *pt++ = lookup12[u.num.num1]; - *pt = '\0'; /* help doing printk */ - info->fake.len += 4; - info->msdos_reject = 0; /* Avoid mangling twice */ - } + if (info->msdos_reject){ + /* #Specification: file name / non MSDOS conforming / mangling + Each non MSDOS conforming file has a special extension + build from the entry position in the EMD file. + + This number is then transform in a base 32 number, where + each digit is expressed like hexadecimal number, using + digit and letter, except it uses 22 letters from 'a' to 'v'. + The number 32 comes from 2**5. It is faster to split a binary + number using a base which is a power of two. And I was 32 + when I started this project. Pick your answer :-) . + + If the result is '0', it is replace with '_', simply + to make it odd. + + This is true for the first two character of the extension. + The last one is taken from a list of odd character, which + are: + + { } ( ) ! ` ^ & @ + + With this scheme, we can produce 9216 ( 9* 32 * 32) + different extensions which should not clash with any useful + extension already popular or meaningful. Since most directory + have much less than 32 * 32 files in it, the first character + of the extension of any mangle name will be {. + + Here are the reason to do this (this kind of mangling). + + -The mangling is deterministic. Just by the extension, we + are able to locate the entry in the EMD file. + + -By keeping to beginning of the file name almost unchanged, + we are helping the MSDOS user. + + -The mangling produces names not too ugly, so an msdos user + may live with it (remember it, type it, etc...). + + -The mangling produces names ugly enough so no one will + ever think of using such a name in real life. This is not + fool proof. I don't think there is a total solution to this. + */ + union { + int entry_num; + struct { + unsigned num1:5,num2:5,num3:5; + }num; + } u; + char *pt = info->fake.fname + info->fake.len; + /* lookup for encoding the last character of the extension */ + /* It contain valid character after the ugly one to make sure */ + /* even if someone overflow the 32 * 32 * 9 limit, it still do */ + /* something */ +#define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@' + static char lookup3[]={ + SPECIAL_MANGLING, + /* This is the start of lookup12 */ + '_','1','2','3','4','5','6','7','8','9', + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', + 'p','q','r','s','t','u','v' + }; +#define lookup12 (lookup3+9) + u.entry_num = info->f_pos / UMSDOS_REC_SIZE; + if (u.entry_num > (9* 32 * 32)){ + printk ("UMSDOS: More than 9216 file in a directory.\n" + "This may break the mangling strategy.\n" + "Not a killer problem. See doc.\n"); + } + *pt++ = '.'; + *pt++ = lookup3 [u.num.num3]; + *pt++ = lookup12[u.num.num2]; + *pt++ = lookup12[u.num.num1]; + *pt = '\0'; /* help doing printk */ + info->fake.len += 4; + info->msdos_reject = 0; /* Avoid mangling twice */ + } } /* - Evaluate the record size needed to store of name of len character. - The value returned is a multiple of UMSDOS_REC_SIZE. + Evaluate the record size needed to store of name of len character. + The value returned is a multiple of UMSDOS_REC_SIZE. */ int umsdos_evalrecsize (int len) { - struct umsdos_dirent dirent; - int nbrec = 1+((len-1+(dirent.name-(char*)&dirent)) - / UMSDOS_REC_SIZE); - return nbrec * UMSDOS_REC_SIZE; - /* - GLU This should be inlined or something to speed it up to the max. - GLU nbrec is absolutely not needed to return the value. - */ + struct umsdos_dirent dirent; + int nbrec = 1+((len-1+(dirent.name-(char*)&dirent)) + / UMSDOS_REC_SIZE); + return nbrec * UMSDOS_REC_SIZE; + /* + GLU This should be inlined or something to speed it up to the max. + GLU nbrec is absolutely not needed to return the value. + */ } #ifdef TEST int umsdos_evalrecsize_old (int len) { - struct umsdos_dirent dirent; - int size = len + (dirent.name-(char*)&dirent); - int nbrec = size / UMSDOS_REC_SIZE; - int extra = size % UMSDOS_REC_SIZE; - if (extra > 0) nbrec++; - return nbrec * UMSDOS_REC_SIZE; + struct umsdos_dirent dirent; + int size = len + (dirent.name-(char*)&dirent); + int nbrec = size / UMSDOS_REC_SIZE; + int extra = size % UMSDOS_REC_SIZE; + if (extra > 0) nbrec++; + return nbrec * UMSDOS_REC_SIZE; } #endif + + /* - Fill the struct info with the full and msdos name of a file - Return 0 if all is ok, a negative error code otherwise. + Fill the struct info with the full and msdos name of a file + Return 0 if all is ok, a negative error code otherwise. */ int umsdos_parse ( - const char *fname, - int len, - struct umsdos_info *info) + const char *fname, + int len, + struct umsdos_info *info) { - int ret = -ENAMETOOLONG; - /* #Specification: file name / too long - If a file name exceed UMSDOS maxima, the file name is silently - truncated. This makes it conformant with the other file system - of Linux (minix and ext2 at least). - */ - if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME; - { - const char *firstpt=NULL; /* First place we saw a . in fname */ - /* #Specification: file name / non MSDOS conforming / base length 0 - file name beginning with a period '.' are invalid for MsDOS. - It needs absolutely a base name. So the file name is mangled - */ - int ivldchar = fname[0] == '.';/* At least one invalid character */ - int msdos_len = len; - int base_len; - /* - cardinal_per_size tells if there exist at least one - DOS pseudo devices on length n. See the test below. - */ - static const char cardinal_per_size[9]={ - 0, 0, 0, 1, 1, 0, 1, 0, 1 - }; - /* - lkp translate all character to acceptable character (for DOS). - When lkp[n] == n, it means also it is an acceptable one. - So it serve both as a flag and as a translator. - */ - static char lkp[256]; - static char is_init=0; - if (!is_init){ - /* - Initialisation of the array is easier and less error prone - like this. - */ - int i; - static const char *spc = "\"*+,/:;<=>?[\\]|~"; - is_init = 1; - for (i=0; i<=32; i++) lkp[i] = '#'; - for (i=33; i<'A'; i++) lkp[i] = (char)i; - for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A')); - for (i='Z'+1; i<127; i++) lkp[i] = (char)i; - for (i=128; i<256; i++) lkp[i] = '#'; - - lkp['.'] = '_'; - while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#'; - } - /* GLU - file name which are longer than 8+'.'+3 are invalid for MsDOS. - So the file name is to be mangled no more test needed. - This Speed Up for long and very long name. - The position of the last point is no more necessary anyway. - */ - if (len<=(8+1+3)){ - const char *pt = fname; - const char *endpt = fname + len; - while (pt < endpt){ - if (*pt == '.'){ - if (firstpt != NULL){ - /* 2 . in a file name. Reject */ - ivldchar = 1; - break; - }else{ - int extlen = (int)(endpt - pt); - firstpt = pt; - if (firstpt - fname > 8){ - /* base name longer than 8: reject */ - ivldchar = 1; - break; - }else if (extlen > 4){ - /* Extension longer than 4 (including .): reject */ - ivldchar = 1; - break; - }else if (extlen == 1){ - /* #Specification: file name / non MSDOS conforming / last char == . - If the last character of a file name is - a period, mangling is applied. MsDOS do - not support those file name. - */ - ivldchar = 1; - break; - }else if (extlen == 4){ - /* #Specification: file name / non MSDOS conforming / mangling clash - To avoid clash with the umsdos mangling, any file - with a special character as the first character - of the extension will be mangled. This solve the - following problem: - - # - touch FILE - # FILE is invalid for DOS, so mangling is applied - # file.{_1 is created in the DOS directory - touch file.{_1 - # To UMSDOS file point to a single DOS entry. - # So file.{_1 has to be mangled. - # - */ - static char special[]={ - SPECIAL_MANGLING,'\0' - }; - if (strchr(special,firstpt[1])!= NULL){ - ivldchar = 1; - break; - } - } - } - }else if (lkp[(unsigned char)(*pt)] != *pt){ - ivldchar = 1; - break; - } - pt++; - } - }else{ - ivldchar = 1; - } - if (ivldchar - || (firstpt == NULL && len > 8) - || (len == UMSDOS_EMD_NAMELEN - && memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){ - /* #Specification: file name / --linux-.--- - The name of the EMD file --linux-.--- is map to a mangled - name. So UMSDOS does not restrict its use. - */ - /* #Specification: file name / non MSDOS conforming / mangling - Non MSDOS conforming file name must use some alias to fit - in the MSDOS name space. - - The strategy is simple. The name is simply truncated to - 8 char. points are replace with underscore and a - number is given as an extension. This number correspond - to the entry number in the EMD file. The EMD file - only need to carry the real name. - - Upper case is also convert to lower case. - Control character are converted to #. - Space are converted to #. - The following character are also converted to #. - # - " * + , / : ; < = > ? [ \ ] | ~ - # - - Sometime, the problem is not in MsDOS itself but in - command.com. - */ - int i; - char *pt = info->fake.fname; - base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len; - /* - There is no '.' any more so we know for a fact that - the base length is the length. - */ - memcpy (info->fake.fname,fname,msdos_len); - for (i=0; imsdos_reject = 1; - /* - The numeric extension is added only when we know - the position in the EMD file, in umsdos_newentry(), - umsdos_delentry(), and umsdos_findentry(). - See umsdos_manglename(). - */ - }else{ - /* Conforming MSDOS file name */ - strncpy (info->fake.fname,fname,len); - info->msdos_reject = 0; - base_len = firstpt != NULL ? (int)(firstpt - fname) : len; - } - if (cardinal_per_size[base_len]){ - /* #Specification: file name / MSDOS devices / mangling - To avoid unreachable file from MsDOS, any MsDOS conforming - file with a basename equal to one of the MsDOS pseudo - devices will be mangled. - - If a file such as "prn" was created, it would be unreachable - under MsDOS because prn is assumed to be the printer, even - if the file does have an extension. - - Since the extension is unimportant to MsDOS, we must patch - the basename also. We simply insert a minus '-'. To avoid - conflict with valid file with a minus in front (such as - "-prn"), we add an mangled extension like any other - mangled file name. - - Here is the list of DOS pseudo devices: - - # - "prn","con","aux","nul", - "lpt1","lpt2","lpt3","lpt4", - "com1","com2","com3","com4", - "clock$" - # - - and some standard ones for common DOS programs - - "emmxxxx0","xmsxxxx0","setverxx" - - (Thanks to Chris Hall - for pointing these to me). - - Is there one missing ? - */ - /* This table must be ordered by length */ - static const char *tbdev[]={ - "prn","con","aux","nul", - "lpt1","lpt2","lpt3","lpt4", - "com1","com2","com3","com4", - "clock$", - "emmxxxx0","xmsxxxx0","setverxx" - }; - /* Tell where to find in tbdev[], the first name of */ - /* a certain length */ - static const char start_ind_dev[9]={ - 0, 0, 0, 4, 12, 12, 13, 13, 16 - }; - char basen[9]; - int i; - for (i=start_ind_dev[base_len-1]; ifake.fname,tbdev[i],base_len)==0){ - memcpy (basen,info->fake.fname,base_len); - basen[base_len] = '\0'; /* GLU C'est sur on a un 0 a la fin */ - /* - GLU On ne fait cela que si necessaire, on essaye d'etre le - GLU simple dans le cas general (le plus frequent). - */ - info->fake.fname[0] = '-'; - strcpy (info->fake.fname+1,basen); /* GLU C'est sur on a un 0 a la fin */ - msdos_len = (base_len==8) ? 8 : base_len + 1; - info->msdos_reject = 1; - break; - } - } - } - info->fake.fname[msdos_len] = '\0'; /* Help doing printk */ - /* GLU Ce zero devrais deja y etre ! (invariant ?) */ - info->fake.len = msdos_len; - /* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/ - memcpy (info->entry.name,fname,len); - info->entry.name_len = len; - ret = 0; + int ret = -ENAMETOOLONG; + /* #Specification: file name / too long + If a file name exceed UMSDOS maxima, the file name is silently + truncated. This makes it conformant with the other file system + of Linux (minix and ext2 at least). + */ + if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME; + { + const char *firstpt=NULL; /* First place we saw a . in fname */ + /* #Specification: file name / non MSDOS conforming / base length 0 + file name beginning with a period '.' are invalid for MsDOS. + It needs absolutely a base name. So the file name is mangled + */ + int ivldchar = fname[0] == '.';/* At least one invalid character */ + int msdos_len = len; + int base_len; + /* + cardinal_per_size tells if there exist at least one + DOS pseudo devices on length n. See the test below. + */ + static const char cardinal_per_size[9]={ + 0, 0, 0, 1, 1, 0, 1, 0, 1 + }; + /* + lkp translate all character to acceptable character (for DOS). + When lkp[n] == n, it means also it is an acceptable one. + So it serve both as a flag and as a translator. + */ + static char lkp[256]; + static char is_init=0; + if (!is_init){ + /* + Initialisation of the array is easier and less error prone + like this. + */ + int i; + static const char *spc = "\"*+,/:;<=>?[\\]|~"; + is_init = 1; + for (i=0; i<=32; i++) lkp[i] = '#'; + for (i=33; i<'A'; i++) lkp[i] = (char)i; + for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A')); + for (i='Z'+1; i<127; i++) lkp[i] = (char)i; + for (i=128; i<256; i++) lkp[i] = '#'; + + lkp['.'] = '_'; + while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#'; + } + /* GLU + file name which are longer than 8+'.'+3 are invalid for MsDOS. + So the file name is to be mangled no more test needed. + This Speed Up for long and very long name. + The position of the last point is no more necessary anyway. + */ + if (len<=(8+1+3)){ + const char *pt = fname; + const char *endpt = fname + len; + while (pt < endpt){ + if (*pt == '.'){ + if (firstpt != NULL){ + /* 2 . in a file name. Reject */ + ivldchar = 1; + break; + }else{ + int extlen = (int)(endpt - pt); + firstpt = pt; + if (firstpt - fname > 8){ + /* base name longer than 8: reject */ + ivldchar = 1; + break; + }else if (extlen > 4){ + /* Extension longer than 4 (including .): reject */ + ivldchar = 1; + break; + }else if (extlen == 1){ + /* #Specification: file name / non MSDOS conforming / last char == . + If the last character of a file name is + a period, mangling is applied. MsDOS do + not support those file name. + */ + ivldchar = 1; + break; + }else if (extlen == 4){ + /* #Specification: file name / non MSDOS conforming / mangling clash + To avoid clash with the umsdos mangling, any file + with a special character as the first character + of the extension will be mangled. This solve the + following problem: + + # + touch FILE + # FILE is invalid for DOS, so mangling is applied + # file.{_1 is created in the DOS directory + touch file.{_1 + # To UMSDOS file point to a single DOS entry. + # So file.{_1 has to be mangled. + # + */ + static char special[]={ + SPECIAL_MANGLING,'\0' + }; + if (strchr(special,firstpt[1])!= NULL){ + ivldchar = 1; + break; + } + } + } + }else if (lkp[(unsigned char)(*pt)] != *pt){ + ivldchar = 1; + break; } - /* - Evaluate how many record are needed to store this entry. - */ - info->recsize = umsdos_evalrecsize (len); - return ret; + pt++; + } + }else{ + ivldchar = 1; + } + if (ivldchar + || (firstpt == NULL && len > 8) + || (len == UMSDOS_EMD_NAMELEN + && memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){ + /* #Specification: file name / --linux-.--- + The name of the EMD file --linux-.--- is map to a mangled + name. So UMSDOS does not restrict its use. + */ + /* #Specification: file name / non MSDOS conforming / mangling + Non MSDOS conforming file name must use some alias to fit + in the MSDOS name space. + + The strategy is simple. The name is simply truncated to + 8 char. points are replace with underscore and a + number is given as an extension. This number correspond + to the entry number in the EMD file. The EMD file + only need to carry the real name. + + Upper case is also convert to lower case. + Control character are converted to #. + Space are converted to #. + The following character are also converted to #. + # + " * + , / : ; < = > ? [ \ ] | ~ + # + + Sometime, the problem is not in MsDOS itself but in + command.com. + */ + int i; + char *pt = info->fake.fname; + base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len; + /* + There is no '.' any more so we know for a fact that + the base length is the length. + */ + memcpy (info->fake.fname,fname,msdos_len); + for (i=0; imsdos_reject = 1; + /* + The numeric extension is added only when we know + the position in the EMD file, in umsdos_newentry(), + umsdos_delentry(), and umsdos_findentry(). + See umsdos_manglename(). + */ + }else{ + /* Conforming MSDOS file name */ + strncpy (info->fake.fname,fname,len); + info->msdos_reject = 0; + base_len = firstpt != NULL ? (int)(firstpt - fname) : len; + } + if (cardinal_per_size[base_len]){ + /* #Specification: file name / MSDOS devices / mangling + To avoid unreachable file from MsDOS, any MsDOS conforming + file with a basename equal to one of the MsDOS pseudo + devices will be mangled. + + If a file such as "prn" was created, it would be unreachable + under MsDOS because prn is assumed to be the printer, even + if the file does have an extension. + + Since the extension is unimportant to MsDOS, we must patch + the basename also. We simply insert a minus '-'. To avoid + conflict with valid file with a minus in front (such as + "-prn"), we add an mangled extension like any other + mangled file name. + + Here is the list of DOS pseudo devices: + + # + "prn","con","aux","nul", + "lpt1","lpt2","lpt3","lpt4", + "com1","com2","com3","com4", + "clock$" + # + + and some standard ones for common DOS programs + + "emmxxxx0","xmsxxxx0","setverxx" + + (Thanks to Chris Hall + for pointing these to me). + + Is there one missing ? + */ + /* This table must be ordered by length */ + static const char *tbdev[]={ + "prn","con","aux","nul", + "lpt1","lpt2","lpt3","lpt4", + "com1","com2","com3","com4", + "clock$", + "emmxxxx0","xmsxxxx0","setverxx" + }; + /* Tell where to find in tbdev[], the first name of */ + /* a certain length */ + static const char start_ind_dev[9]={ + 0, 0, 0, 4, 12, 12, 13, 13, 16 + }; + char basen[9]; + int i; + for (i=start_ind_dev[base_len-1]; ifake.fname,tbdev[i],base_len)==0){ + memcpy (basen,info->fake.fname,base_len); + basen[base_len] = '\0'; /* GLU C'est sur on a un 0 a la fin */ + /* + GLU On ne fait cela que si necessaire, on essaye d'etre le + GLU simple dans le cas general (le plus frequent). + */ + info->fake.fname[0] = '-'; + strcpy (info->fake.fname+1,basen); /* GLU C'est sur on a un 0 a la fin */ + msdos_len = (base_len==8) ? 8 : base_len + 1; + info->msdos_reject = 1; + break; + } + } + } + info->fake.fname[msdos_len] = '\0'; /* Help doing printk */ + /* GLU Ce zero devrais deja y etre ! (invariant ?) */ + info->fake.len = msdos_len; + /* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/ + memcpy (info->entry.name,fname,len); + info->entry.name_len = len; + ret = 0; + } + /* + Evaluate how many record are needed to store this entry. + */ + info->recsize = umsdos_evalrecsize (len); + return ret; } #ifdef TEST struct MANG_TEST{ - char *fname; /* Name to validate */ - int msdos_reject; /* Expected msdos_reject flag */ - char *msname; /* Expected msdos name */ + char *fname; /* Name to validate */ + int msdos_reject; /* Expected msdos_reject flag */ + char *msname; /* Expected msdos name */ }; struct MANG_TEST tb[]={ - "hello", 0, "hello", - "hello.1", 0, "hello.1", - "hello.1_", 0, "hello.1_", - "prm", 0, "prm", - + "hello", 0, "hello", + "hello.1", 0, "hello.1", + "hello.1_", 0, "hello.1_", + "prm", 0, "prm", + #ifdef PROPOSITION - "HELLO", 1, "hello", - "Hello.1", 1, "hello.1", - "Hello.c", 1, "hello.c", + "HELLO", 1, "hello", + "Hello.1", 1, "hello.1", + "Hello.c", 1, "hello.c", #elseif /* - Je trouve les trois exemples ci-dessous tres "malheureux". - Je propose de mettre en minuscule dans un passe preliminaire, - et de tester apres si il y a d'autres caracters "mechants". - Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement - modifiable que ca. Mais c'est pour le principe. - Evidemment cela augmente les chances de "Collision", - par exemple: entre "HELLO" et "Hello", mais ces problemes - peuvent etre traiter ailleur avec les autres collisions. + Je trouve les trois exemples ci-dessous tres "malheureux". + Je propose de mettre en minuscule dans un passe preliminaire, + et de tester apres si il y a d'autres caracters "mechants". + Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement + modifiable que ca. Mais c'est pour le principe. + Evidemment cela augmente les chances de "Collision", + par exemple: entre "HELLO" et "Hello", mais ces problemes + peuvent etre traiter ailleur avec les autres collisions. */ - "HELLO", 1, "hello", - "Hello.1", 1, "hello_1", - "Hello.c", 1, "hello_c", + "HELLO", 1, "hello", + "Hello.1", 1, "hello_1", + "Hello.c", 1, "hello_c", #endif - - "hello.{_1", 1, "hello_{_", - "hello\t", 1, "hello#", - "hello.1.1", 1, "hello_1_", - "hel,lo", 1, "hel#lo", - "Salut.Tu.vas.bien?", 1, "salut_tu", - ".profile", 1, "_profile", - ".xv", 1, "_xv", - "toto.", 1, "toto_", - "clock$.x", 1, "-clock$", - "emmxxxx0", 1, "-emmxxxx", - "emmxxxx0.abcd", 1, "-emmxxxx", - "aux", 1, "-aux", - "prn", 1, "-prn", - "prn.abc", 1, "-prn", - "PRN", 1, "-prn", -/* -GLU ATTENTION : Le resultat de ceux-ci sont differents avec ma version -GLU du mangle par rapport au mangle originale. -GLU CAUSE: La maniere de calculer la variable baselen. -GLU Pour toi c'est toujours 3 -GLU Pour moi c'est respectivement 7, 8 et 8 -*/ - "PRN.abc", 1, "prn_abc", - "Prn.abcd", 1, "prn_abcd", - "prn.abcd", 1, "prn_abcd", - "Prn.abcdefghij", 1, "prn_abcd" + + "hello.{_1", 1, "hello_{_", + "hello\t", 1, "hello#", + "hello.1.1", 1, "hello_1_", + "hel,lo", 1, "hel#lo", + "Salut.Tu.vas.bien?", 1, "salut_tu", + ".profile", 1, "_profile", + ".xv", 1, "_xv", + "toto.", 1, "toto_", + "clock$.x", 1, "-clock$", + "emmxxxx0", 1, "-emmxxxx", + "emmxxxx0.abcd", 1, "-emmxxxx", + "aux", 1, "-aux", + "prn", 1, "-prn", + "prn.abc", 1, "-prn", + "PRN", 1, "-prn", + /* + GLU ATTENTION : Le resultat de ceux-ci sont differents avec ma version + GLU du mangle par rapport au mangle originale. + GLU CAUSE: La maniere de calculer la variable baselen. + GLU Pour toi c'est toujours 3 + GLU Pour moi c'est respectivement 7, 8 et 8 + */ + "PRN.abc", 1, "prn_abc", + "Prn.abcd", 1, "prn_abcd", + "prn.abcd", 1, "prn_abcd", + "Prn.abcdefghij", 1, "prn_abcd" }; int main (int argc, char *argv[]) { - int i,rold,rnew; - printf ("Testing the umsdos_parse.\n"); - for (i=0; ifname,strlen(pttb->fname),&info); - if (strcmp(info.fake.fname,pttb->msname)!=0){ - printf ("**** %s -> ",pttb->fname); - printf ("%s <> %s\n",info.fake.fname,pttb->msname); - }else if (info.msdos_reject != pttb->msdos_reject){ - printf ("**** %s -> %s ",pttb->fname,pttb->msname); - printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject); - }else{ - printf (" %s -> %s %d\n",pttb->fname,pttb->msname - ,pttb->msdos_reject); - } - } - printf ("Testing the new umsdos_evalrecsize."); - for (i=0; ifname,strlen(pttb->fname),&info); + if (strcmp(info.fake.fname,pttb->msname)!=0){ + printf ("**** %s -> ",pttb->fname); + printf ("%s <> %s\n",info.fake.fname,pttb->msname); + }else if (info.msdos_reject != pttb->msdos_reject){ + printf ("**** %s -> %s ",pttb->fname,pttb->msname); + printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject); + }else{ + printf (" %s -> %s %d\n",pttb->fname,pttb->msname + ,pttb->msdos_reject); + } + } + printf ("Testing the new umsdos_evalrecsize."); + for (i=0; iu.umsdos_i.u.dir_info.creating - && dir->u.umsdos_i.u.dir_info.pid != current->pid){ - sleep_on(&dir->u.umsdos_i.u.dir_info.p); - ret = 1; - } - return ret; + int ret = 0; + if (dir->u.umsdos_i.u.dir_info.creating + && dir->u.umsdos_i.u.dir_info.pid != current->pid){ + sleep_on(&dir->u.umsdos_i.u.dir_info.p); + ret = 1; + } + return ret; } /* Wait for any lookup process to finish */ static void umsdos_waitlookup (struct inode *dir) { - while (dir->u.umsdos_i.u.dir_info.looking){ - sleep_on(&dir->u.umsdos_i.u.dir_info.p); - } + while (dir->u.umsdos_i.u.dir_info.looking){ + sleep_on(&dir->u.umsdos_i.u.dir_info.p); + } } /* Lock all other process out of this directory. */ void umsdos_lockcreate (struct inode *dir) { - /* #Specification: file creation / not atomic - File creation is a two step process. First we create (allocate) - an entry in the EMD file and then (using the entry offset) we - build a unique name for MSDOS. We create this name in the msdos - space. - - We have to use semaphore (sleep_on/wake_up) to prevent lookup - into a directory when we create a file or directory and to - prevent creation while a lookup is going on. Since many lookup - may happen at the same time, the semaphore is a counter. - - Only one creation is allowed at the same time. This protection - may not be necessary. The problem arise mainly when a lookup - or a readdir is done while a file is partially created. The - lookup process see that as a "normal" problem and silently - erase the file from the EMD file. Normal because a file - may be erased during a MSDOS session, but not removed from - the EMD file. - - The locking is done on a directory per directory basis. Each - directory inode has its wait_queue. - - For some operation like hard link, things even get worse. Many - creation must occur at once (atomic). To simplify the design - a process is allowed to recursively lock the directory for - creation. The pid of the locking process is kept along with - a counter so a second level of locking is granted or not. - */ - /* - Wait for any creation process to finish except - if we (the process) own the lock - */ - while (umsdos_waitcreate(dir)!=0); - dir->u.umsdos_i.u.dir_info.creating++; - dir->u.umsdos_i.u.dir_info.pid = current->pid; - umsdos_waitlookup (dir); + /* #Specification: file creation / not atomic + File creation is a two step process. First we create (allocate) + an entry in the EMD file and then (using the entry offset) we + build a unique name for MSDOS. We create this name in the msdos + space. + + We have to use semaphore (sleep_on/wake_up) to prevent lookup + into a directory when we create a file or directory and to + prevent creation while a lookup is going on. Since many lookup + may happen at the same time, the semaphore is a counter. + + Only one creation is allowed at the same time. This protection + may not be necessary. The problem arise mainly when a lookup + or a readdir is done while a file is partially created. The + lookup process see that as a "normal" problem and silently + erase the file from the EMD file. Normal because a file + may be erased during a MSDOS session, but not removed from + the EMD file. + + The locking is done on a directory per directory basis. Each + directory inode has its wait_queue. + + For some operation like hard link, things even get worse. Many + creation must occur at once (atomic). To simplify the design + a process is allowed to recursively lock the directory for + creation. The pid of the locking process is kept along with + a counter so a second level of locking is granted or not. + */ + /* + Wait for any creation process to finish except + if we (the process) own the lock + */ + while (umsdos_waitcreate(dir)!=0); + dir->u.umsdos_i.u.dir_info.creating++; + dir->u.umsdos_i.u.dir_info.pid = current->pid; + umsdos_waitlookup (dir); } /* Lock all other process out of those two directories. */ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) { - /* - We must check that both directory are available before - locking anyone of them. This is to avoid some deadlock. - Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing - this to me. - */ - while (1){ - if (umsdos_waitcreate(dir1)==0 - && umsdos_waitcreate(dir2)==0){ - /* We own both now */ - dir1->u.umsdos_i.u.dir_info.creating++; - dir1->u.umsdos_i.u.dir_info.pid = current->pid; - dir2->u.umsdos_i.u.dir_info.creating++; - dir2->u.umsdos_i.u.dir_info.pid = current->pid; - break; - } - } - umsdos_waitlookup(dir1); - umsdos_waitlookup(dir2); + /* + We must check that both directory are available before + locking anyone of them. This is to avoid some deadlock. + Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing + this to me. + */ + while (1){ + if (umsdos_waitcreate(dir1)==0 + && umsdos_waitcreate(dir2)==0){ + /* We own both now */ + dir1->u.umsdos_i.u.dir_info.creating++; + dir1->u.umsdos_i.u.dir_info.pid = current->pid; + dir2->u.umsdos_i.u.dir_info.creating++; + dir2->u.umsdos_i.u.dir_info.pid = current->pid; + break; + } + } + umsdos_waitlookup(dir1); + umsdos_waitlookup(dir2); } /* Wait until creation is finish in this directory. */ void umsdos_startlookup (struct inode *dir) { - while (umsdos_waitcreate (dir) != 0); - dir->u.umsdos_i.u.dir_info.looking++; + while (umsdos_waitcreate (dir) != 0); + dir->u.umsdos_i.u.dir_info.looking++; } /* @@ -129,25 +129,27 @@ */ void umsdos_unlockcreate (struct inode *dir) { - dir->u.umsdos_i.u.dir_info.creating--; - if (dir->u.umsdos_i.u.dir_info.creating < 0){ - printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d" - ,dir->u.umsdos_i.u.dir_info.creating); - } - wake_up (&dir->u.umsdos_i.u.dir_info.p); + dir->u.umsdos_i.u.dir_info.creating--; + if (dir->u.umsdos_i.u.dir_info.creating < 0){ + printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d" + ,dir->u.umsdos_i.u.dir_info.creating); + } + wake_up (&dir->u.umsdos_i.u.dir_info.p); } + /* Tell directory lookup is over. */ void umsdos_endlookup (struct inode *dir) { - dir->u.umsdos_i.u.dir_info.looking--; - if (dir->u.umsdos_i.u.dir_info.looking < 0){ - printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d" - ,dir->u.umsdos_i.u.dir_info.looking); - } - wake_up (&dir->u.umsdos_i.u.dir_info.p); + dir->u.umsdos_i.u.dir_info.looking--; + if (dir->u.umsdos_i.u.dir_info.looking < 0){ + printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d" + ,dir->u.umsdos_i.u.dir_info.looking); + } + wake_up (&dir->u.umsdos_i.u.dir_info.p); } + #else static void umsdos_lockcreate (struct inode *dir){} static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){} @@ -156,152 +158,155 @@ void umsdos_endlookup (struct inode *dir){} #endif static int umsdos_nevercreat( - struct inode *dir, - const char *name, /* Name of the file to add */ - int len, - int errcod) /* Length of the name */ + struct inode *dir, + struct dentry *dentry, + int errcod) /* Length of the name */ { - int ret = 0; - if (umsdos_is_pseudodos(dir,name,len)){ - /* #Specification: pseudo root / any file creation /DOS - The pseudo sub-directory /DOS can't be created! - EEXIST is returned. - - The pseudo sub-directory /DOS can't be removed! - EPERM is returned. - */ - ret = -EPERM; - ret = errcod; - }else if (name[0] == '.' - && (len == 1 || (len == 2 && name[1] == '.'))){ - /* #Specification: create / . and .. - If one try to creates . or .., it always fail and return - EEXIST. - - If one try to delete . or .., it always fail and return - EPERM. - - This should be test at the VFS layer level to avoid - duplicating this in all file systems. Any comments ? - */ - ret = errcod; - } - return ret; + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; + int ret = 0; + if (umsdos_is_pseudodos(dir,dentry)){ + /* #Specification: pseudo root / any file creation /DOS + The pseudo sub-directory /DOS can't be created! + EEXIST is returned. + + The pseudo sub-directory /DOS can't be removed! + EPERM is returned. + */ + ret = -EPERM; + ret = errcod; + }else if (name[0] == '.' + && (len == 1 || (len == 2 && name[1] == '.'))){ + /* #Specification: create / . and .. + If one try to creates . or .., it always fail and return + EEXIST. + + If one try to delete . or .., it always fail and return + EPERM. + + This should be test at the VFS layer level to avoid + duplicating this in all file systems. Any comments ? + */ + ret = errcod; + } + return ret; } /* - Add a new file (ordinary or special) into the alternate directory. - The file is added to the real MSDOS directory. If successful, it - is then added to the EDM file. - - Return the status of the operation. 0 mean success. + Add a new file (ordinary or special) into the alternate directory. + The file is added to the real MSDOS directory. If successful, it + is then added to the EDM file. + + Return the status of the operation. 0 mean success. */ static int umsdos_create_any ( - struct inode *dir, - const char *name, /* Name of the file to add */ - int len, /* Length of the name */ - int mode, /* Permission bit + file type ??? */ - int rdev, /* major, minor or 0 for ordinary file */ - /* and symlinks */ - char flags, - struct inode **result) /* Will hold the inode of the newly created */ - /* file */ + struct inode *dir, + struct dentry *dentry, /* name/length etc*/ + int mode, /* Permission bit + file type ??? */ + int rdev, /* major, minor or 0 for ordinary file */ + /* and symlinks */ + char flags + ) /* Will hold the inode of the newly created */ + /* file */ { - int ret = umsdos_nevercreat(dir,name,len,-EEXIST); + + int ret = umsdos_nevercreat(dir,dentry,-EEXIST); + if (ret == 0){ + struct umsdos_info info; + ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info); + + if (ret == 0){ + info.entry.mode = mode; + info.entry.rdev = rdev; + info.entry.flags = flags; + info.entry.uid = current->fsuid; + info.entry.gid = (dir->i_mode & S_ISGID) + ? dir->i_gid : current->fsgid; + info.entry.ctime = info.entry.atime = info.entry.mtime + = CURRENT_TIME; + info.entry.nlink = 1; + umsdos_lockcreate(dir); + ret = umsdos_newentry (dir,&info); + if (ret == 0){ + dir->i_count++; + /* FIXME + ret = msdos_create (dir,info.fake.fname,info.fake.len + ,S_IFREG|0777,result); + */ + ret =msdos_create(dir,dentry,S_IFREG|0777); if (ret == 0){ - struct umsdos_info info; - ret = umsdos_parse (name,len,&info); - *result = NULL; - if (ret == 0){ - info.entry.mode = mode; - info.entry.rdev = rdev; - info.entry.flags = flags; - info.entry.uid = current->fsuid; - info.entry.gid = (dir->i_mode & S_ISGID) - ? dir->i_gid : current->fsgid; - info.entry.ctime = info.entry.atime = info.entry.mtime - = CURRENT_TIME; - info.entry.nlink = 1; - umsdos_lockcreate(dir); - ret = umsdos_newentry (dir,&info); - if (ret == 0){ - atomic_inc(&dir->i_count); - ret = msdos_create (dir,info.fake.fname,info.fake.len - ,S_IFREG|0777,result); - if (ret == 0){ - struct inode *inode = *result; - umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - PRINTK (("inode %p[%d] ",inode, - atomic_read(&inode->i_count))); - PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino - ,info.fake.fname,current->pid,info.f_pos)); - }else{ - /* #Specification: create / file exist in DOS - Here is a situation. Trying to create a file with - UMSDOS. The file is unknown to UMSDOS but already - exist in the DOS directory. - - Here is what we are NOT doing: - - We could silently assume that everything is fine - and allows the creation to succeed. - - It is possible not all files in the partition - are mean to be visible from linux. By trying to create - those file in some directory, one user may get access - to those file without proper permissions. Looks like - a security hole to me. Off course sharing a file system - with DOS is some kind of security hole :-) - - So ? - - We return EEXIST in this case. - The same is true for directory creation. - */ - if (ret == -EEXIST){ - printk ("UMSDOS: out of sync, Creation error [%ld], " - "deleting %s %d %d pos %ld\n",dir->i_ino - ,info.fake.fname,-ret,current->pid,info.f_pos); - } - umsdos_delentry (dir,&info,0); - } - PRINTK (("umsdos_create %s ret = %d pos %d\n" - ,info.fake.fname,ret,info.f_pos)); - } - umsdos_unlockcreate(dir); - } + struct inode *inode = dentry->d_inode; + umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); + Printk (("inode %p[%d] ",inode,inode->i_count)); + Printk (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino + ,info.fake.fname,current->pid,info.f_pos)); + }else{ + /* #Specification: create / file exist in DOS + Here is a situation. Trying to create a file with + UMSDOS. The file is unknown to UMSDOS but already + exist in the DOS directory. + + Here is what we are NOT doing: + + We could silently assume that everything is fine + and allows the creation to succeed. + + It is possible not all files in the partition + are mean to be visible from linux. By trying to create + those file in some directory, one user may get access + to those file without proper permissions. Looks like + a security hole to me. Off course sharing a file system + with DOS is some kind of security hole :-) + + So ? + + We return EEXIST in this case. + The same is true for directory creation. + */ + if (ret == -EEXIST){ + printk ("UMSDOS: out of sync, Creation error [%ld], " + "deleting %s %d %d pos %ld\n",dir->i_ino + ,info.fake.fname,-ret,current->pid,info.f_pos); + } + umsdos_delentry (dir,&info,0); } - iput (dir); - return ret; + Printk (("umsdos_create %s ret = %d pos %d\n" + ,info.fake.fname,ret,info.f_pos)); + } + umsdos_unlockcreate(dir); + } + } + d_add(dentry,dir); + return ret; } /* Initialise the new_entry from the old for a rename operation. (Only useful for umsdos_rename_f() below). */ static void umsdos_ren_init( - struct umsdos_info *new_info, - struct umsdos_info *old_info, - int flags) /* 0 == copy flags from old_name */ - /* != 0, this is the value of flags */ + struct umsdos_info *new_info, + struct umsdos_info *old_info, + int flags) /* 0 == copy flags from old_name */ + /* != 0, this is the value of flags */ { - new_info->entry.mode = old_info->entry.mode; - new_info->entry.rdev = old_info->entry.rdev; - new_info->entry.uid = old_info->entry.uid; - new_info->entry.gid = old_info->entry.gid; - new_info->entry.ctime = old_info->entry.ctime; - new_info->entry.atime = old_info->entry.atime; - new_info->entry.mtime = old_info->entry.mtime; - new_info->entry.flags = flags ? flags : old_info->entry.flags; - new_info->entry.nlink = old_info->entry.nlink; + new_info->entry.mode = old_info->entry.mode; + new_info->entry.rdev = old_info->entry.rdev; + new_info->entry.uid = old_info->entry.uid; + new_info->entry.gid = old_info->entry.gid; + new_info->entry.ctime = old_info->entry.ctime; + new_info->entry.atime = old_info->entry.atime; + new_info->entry.mtime = old_info->entry.mtime; + new_info->entry.flags = flags ? flags : old_info->entry.flags; + new_info->entry.nlink = old_info->entry.nlink; } #define chkstk() \ - if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\ - printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \ - , current->comm,STACK_MAGIC \ - ,*(unsigned long *)current->kernel_stack_page \ - ,__LINE__); \ - } +if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\ + printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \ + , current->comm,STACK_MAGIC \ + ,*(unsigned long *)current->kernel_stack_page \ + ,__LINE__); \ +} #undef chkstk #define chkstk() do { } while (0) @@ -310,798 +315,802 @@ Rename a file (move) in the file system. */ static int umsdos_rename_f( - struct inode * old_dir, - const char * old_name, - int old_len, - struct inode * new_dir, - const char * new_name, - int new_len, - int flags) /* 0 == copy flags from old_name */ - /* != 0, this is the value of flags */ + struct inode * old_dir, + struct dentry *old_dentry, + struct inode * new_dir, + struct dentry *new_dentry, + int flags) /* 0 == copy flags from old_name */ + /* != 0, this is the value of flags */ { - int ret = -EPERM; - struct umsdos_info old_info; - int old_ret = umsdos_parse (old_name,old_len,&old_info); - struct umsdos_info new_info; - int new_ret = umsdos_parse (new_name,new_len,&new_info); -chkstk(); - PRINTK (("umsdos_rename %d %d ",old_ret,new_ret)); - if (old_ret == 0 && new_ret == 0){ - umsdos_lockcreate2(old_dir,new_dir); -chkstk(); - PRINTK (("old findentry ")); - ret = umsdos_findentry(old_dir,&old_info,0); -chkstk(); - PRINTK (("ret %d ",ret)); - if (ret == 0){ - /* check sticky bit on old_dir */ - if ( !(old_dir->i_mode & S_ISVTX) || - current->fsuid == old_info.entry.uid || - current->fsuid == old_dir->i_uid || - fsuser()) { - /* Does new_name already exist? */ - PRINTK(("new findentry ")); - ret = umsdos_findentry(new_dir,&new_info,0); - if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ - !(new_dir->i_mode & S_ISVTX) || - current->fsuid == new_info.entry.uid || - current->fsuid == new_dir->i_uid || - fsuser()) { - PRINTK (("new newentry ")); - umsdos_ren_init(&new_info,&old_info,flags); - ret = umsdos_newentry (new_dir,&new_info); -chkstk(); - PRINTK (("ret %d %d ",ret,new_info.fake.len)); - if (ret == 0){ - PRINTK (("msdos_rename ")); - atomic_inc(&old_dir->i_count); - atomic_inc(&new_dir->i_count); /* Both inode are needed later */ - ret = msdos_rename (old_dir - ,old_info.fake.fname,old_info.fake.len - ,new_dir - ,new_info.fake.fname,new_info.fake.len); -chkstk(); - PRINTK (("after m_rename ret %d ",ret)); - if (ret != 0){ - umsdos_delentry (new_dir,&new_info - ,S_ISDIR(new_info.entry.mode)); -chkstk(); - }else{ - ret = umsdos_delentry (old_dir,&old_info - ,S_ISDIR(old_info.entry.mode)); -chkstk(); - if (ret == 0){ - /* - This UMSDOS_lookup does not look very useful. - It makes sure that the inode of the file will - be correctly setup (umsdos_patch_inode()) in - case it is already in use. - - Not very efficient ... - */ - struct inode *inode; - atomic_inc(&new_dir->i_count); - PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags)); - ret = UMSDOS_lookup (new_dir,new_name,new_len - ,&inode); -chkstk(); - if (ret != 0){ - printk ("UMSDOS: partial rename for file %s\n" - ,new_info.entry.name); - }else{ - /* - Update f_pos so notify_change will succeed - if the file was already in use. - */ - umsdos_set_dirinfo (inode,new_dir,new_info.f_pos); -chkstk(); - iput (inode); - } - } - } - } - }else{ - /* sticky bit set on new_dir */ - PRINTK(("sticky set on new ")); - ret = -EPERM; - } - }else{ - /* sticky bit set on old_dir */ - PRINTK(("sticky set on old ")); - ret = -EPERM; - } + int ret = -EPERM; + struct umsdos_info old_info; + int old_ret = umsdos_parse (old_dentry->d_name.name, + old_dentry->d_name.len,&old_info); + struct umsdos_info new_info; + int new_ret = umsdos_parse (new_dentry->d_name.name, + new_dentry->d_name.len,&new_info); + chkstk(); + Printk (("umsdos_rename %d %d ",old_ret,new_ret)); + if (old_ret == 0 && new_ret == 0){ + umsdos_lockcreate2(old_dir,new_dir); + chkstk(); + Printk (("old findentry ")); + ret = umsdos_findentry(old_dir,&old_info,0); + chkstk(); + Printk (("ret %d ",ret)); + if (ret == 0){ + /* check sticky bit on old_dir */ + if ( !(old_dir->i_mode & S_ISVTX) || fsuser() || + current->fsuid == old_info.entry.uid || + current->fsuid == old_dir->i_uid ) { + /* Does new_name already exist? */ + PRINTK(("new findentry ")); + ret = umsdos_findentry(new_dir,&new_info,0); + if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ + !(new_dir->i_mode & S_ISVTX) || fsuser() || + current->fsuid == new_info.entry.uid || + current->fsuid == new_dir->i_uid ) { + PRINTK (("new newentry ")); + umsdos_ren_init(&new_info,&old_info,flags); + ret = umsdos_newentry (new_dir,&new_info); + chkstk(); + PRINTK (("ret %d %d ",ret,new_info.fake.len)); + if (ret == 0){ + struct dentry *old, *new; + old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL); + new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL); + + PRINTK (("msdos_rename ")); + old_dir->i_count++; + new_dir->i_count++; /* Both inode are needed later */ + ret = msdos_rename (old_dir, + old, + new_dir, + new); + chkstk(); + PRINTK (("after m_rename ret %d ",ret)); + if (ret != 0){ + umsdos_delentry (new_dir,&new_info + ,S_ISDIR(new_info.entry.mode)); + chkstk(); + }else{ + ret = umsdos_delentry (old_dir,&old_info + ,S_ISDIR(old_info.entry.mode)); + chkstk(); + if (ret == 0){ + /* + This UMSDOS_lookup does not look very useful. + It makes sure that the inode of the file will + be correctly setup (umsdos_patch_inode()) in + case it is already in use. + + Not very efficient ... + */ + struct inode *inode; + new_dir->i_count++; + PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags)); + ret = UMSDOS_lookup (new_dir,new_dentry); + inode = new_dentry->d_inode; + chkstk(); + if (ret != 0){ + printk ("UMSDOS: partial rename for file %s\n" + ,new_info.entry.name); + }else{ + /* + Update f_pos so notify_change will succeed + if the file was already in use. + */ + umsdos_set_dirinfo (inode,new_dir,new_info.f_pos); + chkstk(); + /* iput (inode); FIXME */ } - umsdos_unlockcreate(old_dir); - umsdos_unlockcreate(new_dir); + } + } + } + }else{ + /* sticky bit set on new_dir */ + Printk(("sticky set on new ")); + ret = -EPERM; } - iput (old_dir); - iput (new_dir); - PRINTK (("\n")); - return ret; + }else{ + /* sticky bit set on old_dir */ + Printk(("sticky set on old ")); + ret = -EPERM; + } + } + umsdos_unlockcreate(old_dir); + umsdos_unlockcreate(new_dir); + } + d_move(old_dentry,new_dentry); + Printk (("\n")); + return ret; } /* Setup un Symbolic link or a (pseudo) hard link Return a negative error code or 0 if ok. */ static int umsdos_symlink_x( - struct inode * dir, - const char * name, - int len, - const char * symname, /* name will point to this path */ - int mode, - char flags) + struct inode * dir, + struct dentry *dentry, + const char * symname, /* name will point to this path */ + int mode, + char flags) { - /* #Specification: symbolic links / strategy - A symbolic link is simply a file which hold a path. It is - implemented as a normal MSDOS file (not very space efficient :-() - - I see 2 different way to do it. One is to place the link data - in unused entry of the EMD file. The other is to have a separate - file dedicated to hold all symbolic links data. - - Let's go for simplicity... - */ - struct inode *inode; - int ret; - atomic_inc(&dir->i_count);/* We keep the inode in case we need it */ - /* later */ - ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode); - PRINTK (("umsdos_symlink ret %d ",ret)); - if (ret == 0){ - int len = strlen(symname); - struct file filp; - filp.f_pos = 0; - /* Make the inode acceptable to MSDOS */ - ret = umsdos_file_write_kmem (inode,&filp,symname,len); - iput (inode); - if (ret >= 0){ - if (ret != len){ - ret = -EIO; - printk ("UMSDOS: " - "Can't write symbolic link data\n"); - }else{ - ret = 0; - } - } - if (ret != 0){ - UMSDOS_unlink (dir,name,len); - dir = NULL; - } - } - iput (dir); - PRINTK (("\n")); - return ret; + /* #Specification: symbolic links / strategy + A symbolic link is simply a file which hold a path. It is + implemented as a normal MSDOS file (not very space efficient :-() + + I see 2 different way to do it. One is to place the link data + in unused entry of the EMD file. The other is to have a separate + file dedicated to hold all symbolic links data. + + Let's go for simplicity... + */ + + + int ret; + dir->i_count++;/* We keep the inode in case we need it */ + /* later */ + ret = umsdos_create_any (dir,dentry,mode,0,flags); + Printk (("umsdos_symlink ret %d ",ret)); + if (ret == 0){ + int len = strlen(symname); + struct file filp; + filp.f_pos = 0; + /* Make the inode acceptable to MSDOS FIXME */ + Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n")); + ret = umsdos_file_write_kmem (dentry->d_inode->i_ino, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... */ + /* dput(dentry); ?? where did this come from FIXME */ + if (ret >= 0){ + if (ret != len){ + ret = -EIO; + printk ("UMSDOS: " + "Can't write symbolic link data\n"); + }else{ + ret = 0; + } + } + if (ret != 0){ + UMSDOS_unlink (dir,dentry); + dir = NULL; + } + } + d_instantiate(dentry,dir); + Printk (("\n")); + return ret; } /* - Setup un Symbolic link. - Return a negative error code or 0 if ok. + Setup un Symbolic link. + Return a negative error code or 0 if ok. */ int UMSDOS_symlink( - struct inode * dir, - const char * name, - int len, - const char * symname) /* name will point to this path */ + struct inode * dir, + struct dentry *dentry, + const char * symname + ) { - return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0); + return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0); } /* - Add a link to an inode in a directory + Add a link to an inode in a directory */ int UMSDOS_link ( - struct inode * oldinode, - struct inode * dir, - const char * name, - int len) + struct dentry * olddentry, + struct inode * dir, + struct dentry *dentry) { - /* #Specification: hard link / strategy - Well ... hard link are difficult to implement on top of an - MsDOS fat file system. Unlike UNIX file systems, there are no - inode. A directory entry hold the functionality of the inode - and the entry. - - We will used the same strategy as a normal Unix file system - (with inode) except we will do it symbolically (using paths). - - Because anything can happen during a DOS session (defragment, - directory sorting, etc...), we can't rely on MsDOS pseudo - inode number to record the link. For this reason, the link - will be done using hidden symbolic links. The following - scenario illustrate how it work. - - Given a file /foo/file - - # - ln /foo/file /tmp/file2 - - become internally - - mv /foo/file /foo/-LINK1 - ln -s /foo/-LINK1 /foo/file - ln -s /foo/-LINK1 /tmp/file2 - # - - Using this strategy, we can operate on /foo/file or /foo/file2. - We can remove one and keep the other, like a normal Unix hard link. - We can rename /foo/file or /tmp/file2 independently. - - The entry -LINK1 will be hidden. It will hold a link count. - When all link are erased, the hidden file is erased too. - */ - /* #Specification: weakness / hard link - The strategy for hard link introduces a side effect that - may or may not be acceptable. Here is the sequence - - # - mkdir subdir1 - touch subdir1/file - mkdir subdir2 - ln subdir1/file subdir2/file - rm subdir1/file - rmdir subdir1 - rmdir: subdir1: Directory not empty - # - - This happen because there is an invisible file (--link) in - subdir1 which is referenced by subdir2/file. - - Any idea ? - */ - /* #Specification: weakness / hard link / rename directory - Another weakness of hard link come from the fact that - it is based on hidden symbolic links. Here is an example. - - # - mkdir /subdir1 - touch /subdir1/file - mkdir /subdir2 - ln /subdir1/file subdir2/file - mv /subdir1 subdir3 - ls -l /subdir2/file - # - - Since /subdir2/file is a hidden symbolic link - to /subdir1/..hlinkNNN, accessing it will fail since - /subdir1 does not exist anymore (has been renamed). - */ - int ret = 0; - if (S_ISDIR(oldinode->i_mode)){ - /* #Specification: hard link / directory - A hard link can't be made on a directory. EPERM is returned - in this case. - */ - ret = -EPERM; - }else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){ - struct inode *olddir; - ret = umsdos_get_dirowner(oldinode,&olddir); - PRINTK (("umsdos_link dir_owner = %d -> %p [%d] " - ,oldinode->u.umsdos_i.i_dir_owner,olddir, - atomic_read(&olddir->i_count))); + struct inode *oldinode = olddentry->d_inode; + /* #Specification: hard link / strategy + Well ... hard link are difficult to implement on top of an + MsDOS fat file system. Unlike UNIX file systems, there are no + inode. A directory entry hold the functionality of the inode + and the entry. + + We will used the same strategy as a normal Unix file system + (with inode) except we will do it symbolically (using paths). + + Because anything can happen during a DOS session (defragment, + directory sorting, etc...), we can't rely on MsDOS pseudo + inode number to record the link. For this reason, the link + will be done using hidden symbolic links. The following + scenario illustrate how it work. + + Given a file /foo/file + + # + ln /foo/file /tmp/file2 + + become internally + + mv /foo/file /foo/-LINK1 + ln -s /foo/-LINK1 /foo/file + ln -s /foo/-LINK1 /tmp/file2 + # + + Using this strategy, we can operate on /foo/file or /foo/file2. + We can remove one and keep the other, like a normal Unix hard link. + We can rename /foo/file or /tmp/file2 independently. + + The entry -LINK1 will be hidden. It will hold a link count. + When all link are erased, the hidden file is erased too. + */ + /* #Specification: weakness / hard link + The strategy for hard link introduces a side effect that + may or may not be acceptable. Here is the sequence + + # + mkdir subdir1 + touch subdir1/file + mkdir subdir2 + ln subdir1/file subdir2/file + rm subdir1/file + rmdir subdir1 + rmdir: subdir1: Directory not empty + # + + This happen because there is an invisible file (--link) in + subdir1 which is referenced by subdir2/file. + + Any idea ? + */ + /* #Specification: weakness / hard link / rename directory + Another weakness of hard link come from the fact that + it is based on hidden symbolic links. Here is an example. + + # + mkdir /subdir1 + touch /subdir1/file + mkdir /subdir2 + ln /subdir1/file subdir2/file + mv /subdir1 subdir3 + ls -l /subdir2/file + # + + Since /subdir2/file is a hidden symbolic link + to /subdir1/..hlinkNNN, accessing it will fail since + /subdir1 does not exist anymore (has been renamed). + */ + int ret = 0; + if (S_ISDIR(oldinode->i_mode)){ + /* #Specification: hard link / directory + A hard link can't be made on a directory. EPERM is returned + in this case. + */ + ret = -EPERM; + }else if ((ret = umsdos_nevercreat(dir,dentry,-EPERM))==0){ + struct inode *olddir; + ret = umsdos_get_dirowner(oldinode,&olddir); + Printk (("umsdos_link dir_owner = %d -> %p [%d] " + ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count)); + if (ret == 0){ + struct umsdos_dirent entry; + umsdos_lockcreate2(dir,olddir); + ret = umsdos_inode2entry (olddir,oldinode,&entry); + if (ret == 0){ + Printk (("umsdos_link :%s: ino %d flags %d " + ,entry.name + ,oldinode->i_ino,entry.flags)); + if (!(entry.flags & UMSDOS_HIDDEN)){ + /* #Specification: hard link / first hard link + The first time a hard link is done on a file, this + file must be renamed and hidden. Then an internal + symbolic link must be done on the hidden file. + + The second link is done after on this hidden file. + + It is expected that the Linux MSDOS file system + keeps the same pseudo inode when a rename operation + is done on a file in the same directory. + */ + struct umsdos_info info; + ret = umsdos_newhidden (olddir,&info); + if (ret == 0){ + Printk (("olddir[%d] ",olddir->i_count)); + ret = umsdos_rename_f( + olddentry->d_inode, + olddentry, + dir, + dentry, + UMSDOS_HIDDEN); + if (ret == 0){ + char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); + if (path == NULL){ + ret = -ENOMEM; + }else{ + struct dentry *temp; + temp = creat_dentry (entry.name, entry.name_len, NULL); + Printk (("olddir[%d] ",olddir->i_count)); + ret = umsdos_locate_path (oldinode,path); + Printk (("olddir[%d] ",olddir->i_count)); if (ret == 0){ - struct umsdos_dirent entry; - umsdos_lockcreate2(dir,olddir); - ret = umsdos_inode2entry (olddir,oldinode,&entry); - if (ret == 0){ - PRINTK (("umsdos_link :%s: ino %d flags %d " - ,entry.name - ,oldinode->i_ino,entry.flags)); - if (!(entry.flags & UMSDOS_HIDDEN)){ - /* #Specification: hard link / first hard link - The first time a hard link is done on a file, this - file must be renamed and hidden. Then an internal - symbolic link must be done on the hidden file. - - The second link is done after on this hidden file. - - It is expected that the Linux MSDOS file system - keeps the same pseudo inode when a rename operation - is done on a file in the same directory. - */ - struct umsdos_info info; - ret = umsdos_newhidden (olddir,&info); - if (ret == 0){ - atomic_add(2, &olddir->i_count); - PRINTK (("olddir[%d] ", - atomic_read(&olddir->i_count))); - ret = umsdos_rename_f (olddir,entry.name - ,entry.name_len - ,olddir,info.entry.name,info.entry.name_len - ,UMSDOS_HIDDEN); - if (ret == 0){ - char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - if (path == NULL){ - ret = -ENOMEM; - }else{ - PRINTK (("olddir[%d] ", - atomic_read(&olddir->i_count))); - ret = umsdos_locate_path (oldinode,path); - PRINTK (("olddir[%d] ", - atomic_read(&olddir->i_count))); - if (ret == 0){ - atomic_inc(&olddir->i_count); - ret = umsdos_symlink_x (olddir - ,entry.name - ,entry.name_len,path - ,S_IFREG|0777,UMSDOS_HLINK); - if (ret == 0){ - atomic_inc(&dir->i_count); - ret = umsdos_symlink_x (dir,name,len - ,path - ,S_IFREG|0777,UMSDOS_HLINK); - } - } - kfree (path); - } - } - } - }else{ - char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - if (path == NULL){ - ret = -ENOMEM; - }else{ - ret = umsdos_locate_path (oldinode,path); - if (ret == 0){ - atomic_inc(&dir->i_count); - ret = umsdos_symlink_x (dir,name,len,path - ,S_IFREG|0777,UMSDOS_HLINK); - } - kfree (path); - } - } - } - umsdos_unlockcreate(olddir); - umsdos_unlockcreate(dir); + olddir->i_count++; + ret = umsdos_symlink_x (olddir + ,temp + ,path + ,S_IFREG|0777,UMSDOS_HLINK); + if (ret == 0){ + dir->i_count++; + ret = umsdos_symlink_x (dir,dentry, + path, + S_IFREG|0777,UMSDOS_HLINK); + } } - iput (olddir); + kfree (path); + } + } + } + }else{ + char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); + if (path == NULL){ + ret = -ENOMEM; + }else{ + ret = umsdos_locate_path (oldinode,path); + if (ret == 0){ + dir->i_count++; + ret = umsdos_symlink_x (dir,dentry,path + ,S_IFREG|0777,UMSDOS_HLINK); + } + kfree (path); + } } - if (ret == 0){ - struct iattr newattrs; - oldinode->i_nlink++; - newattrs.ia_valid = 0; - ret = UMSDOS_notify_change(oldinode, &newattrs); - } - iput (oldinode); - iput (dir); - PRINTK (("umsdos_link %d\n",ret)); - return ret; + } + umsdos_unlockcreate(olddir); + umsdos_unlockcreate(dir); + } + iput (olddir); + } + if (ret == 0){ + struct iattr newattrs; + oldinode->i_nlink++; + newattrs.ia_valid = 0; + ret = UMSDOS_notify_change(olddentry, &newattrs); + } + dput (olddentry); + dput (dentry); + Printk (("umsdos_link %d\n",ret)); + return ret; } /* - Add a new file into the alternate directory. - The file is added to the real MSDOS directory. If successful, it - is then added to the EDM file. - - Return the status of the operation. 0 mean success. + Add a new file into the alternate directory. + The file is added to the real MSDOS directory. If successful, it + is then added to the EDM file. + + Return the status of the operation. 0 mean success. */ int UMSDOS_create ( - struct inode *dir, - const char *name, /* Name of the file to add */ - int len, /* Length of the name */ - int mode, /* Permission bit + file type ??? */ - struct inode **result) /* Will hold the inode of the newly created */ + struct inode *dir, + struct dentry *dentry, /* Length of the name */ + int mode /* Permission bit + file type ??? */ + ) /* Will hold the inode of the newly created */ /* file */ { - return umsdos_create_any (dir,name,len,mode,0,0,result); + return umsdos_create_any (dir,dentry,mode,0,0); } /* Add a sub-directory in a directory */ int UMSDOS_mkdir( - struct inode * dir, - const char * name, - int len, - int mode) + struct inode * dir, + struct dentry *dentry, + int mode) { - int ret = umsdos_nevercreat(dir,name,len,-EEXIST); - if (ret == 0){ - struct umsdos_info info; - ret = umsdos_parse (name,len,&info); - PRINTK (("umsdos_mkdir %d\n",ret)); - if (ret == 0){ - info.entry.mode = mode | S_IFDIR; - info.entry.rdev = 0; - info.entry.uid = current->fsuid; - info.entry.gid = (dir->i_mode & S_ISGID) - ? dir->i_gid : current->fsgid; - info.entry.ctime = info.entry.atime = info.entry.mtime - = CURRENT_TIME; - info.entry.flags = 0; - umsdos_lockcreate(dir); - info.entry.nlink = 1; - ret = umsdos_newentry (dir,&info); - PRINTK (("newentry %d ",ret)); - if (ret == 0){ - atomic_inc(&dir->i_count); - ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode); - if (ret != 0){ - umsdos_delentry (dir,&info,1); - /* #Specification: mkdir / Directory already exist in DOS - We do the same thing as for file creation. - For all user it is an error. - */ - }else{ - /* #Specification: mkdir / umsdos directory / create EMD - When we created a new sub-directory in a UMSDOS - directory (one with full UMSDOS semantic), we - create immediately an EMD file in the new - sub-directory so it inherit UMSDOS semantic. - */ - struct inode *subdir; - ret = umsdos_real_lookup (dir,info.fake.fname - ,info.fake.len,&subdir); - if (ret == 0){ - struct inode *result; - ret = msdos_create (subdir,UMSDOS_EMD_FILE - ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result); - subdir = NULL; - iput (result); - } - if (ret < 0){ - printk ("UMSDOS: Can't create empty --linux-.---\n"); - } - iput (subdir); - } - } - umsdos_unlockcreate(dir); - } + int ret = umsdos_nevercreat(dir,dentry,-EEXIST); + if (ret == 0){ + struct umsdos_info info; + ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); + Printk (("umsdos_mkdir %d\n",ret)); + if (ret == 0){ + info.entry.mode = mode | S_IFDIR; + info.entry.rdev = 0; + info.entry.uid = current->fsuid; + info.entry.gid = (dir->i_mode & S_ISGID) + ? dir->i_gid : current->fsgid; + info.entry.ctime = info.entry.atime = info.entry.mtime + = CURRENT_TIME; + info.entry.flags = 0; + umsdos_lockcreate(dir); + info.entry.nlink = 1; + ret = umsdos_newentry (dir,&info); + Printk (("newentry %d ",ret)); + if (ret == 0){ + struct dentry *temp; + temp = creat_dentry (info.fake.fname, info.fake.len, NULL); + dir->i_count++; + ret = msdos_mkdir (dir, temp, mode); + if (ret != 0){ + umsdos_delentry (dir,&info,1); + /* #Specification: mkdir / Directory already exist in DOS + We do the same thing as for file creation. + For all user it is an error. + */ + }else{ + /* #Specification: mkdir / umsdos directory / create EMD + When we created a new sub-directory in a UMSDOS + directory (one with full UMSDOS semantic), we + create immediately an EMD file in the new + sub-directory so it inherit UMSDOS semantic. + */ + struct inode *subdir; + ret = compat_umsdos_real_lookup (dir,info.fake.fname, + info.fake.len,&subdir); + if (ret == 0){ + struct inode *result; + struct dentry *tdentry; + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); + + ret = msdos_create (subdir, tdentry,S_IFREG|0777); + subdir = NULL; + /* iput (result); FIXME */ + } + if (ret < 0){ + printk ("UMSDOS: Can't create empty --linux-.---\n"); + } + /* iput (subdir); FIXME */ } - PRINTK (("umsdos_mkdir %d\n",ret)); - iput (dir); - return ret; + } + umsdos_unlockcreate(dir); + } + } + Printk (("umsdos_mkdir %d\n",ret)); + dput (dentry); + return ret; } /* Add a new device special file into a directory. */ int UMSDOS_mknod( struct inode * dir, - const char * name, - int len, + struct dentry *dentry, int mode, int rdev) { - /* #Specification: Special files / strategy - Device special file, pipes, etc ... are created like normal - file in the msdos file system. Of course they remain empty. - - One strategy was to create those files only in the EMD file - since they were not important for MSDOS. The problem with - that, is that there were not getting inode number allocated. - The MSDOS filesystems is playing a nice game to fake inode - number, so why not use it. - - The absence of inode number compatible with those allocated - for ordinary files was causing major trouble with hard link - in particular and other parts of the kernel I guess. - */ - struct inode *inode; - int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode); - iput (inode); - return ret; + /* #Specification: Special files / strategy + Device special file, pipes, etc ... are created like normal + file in the msdos file system. Of course they remain empty. + + One strategy was to create those files only in the EMD file + since they were not important for MSDOS. The problem with + that, is that there were not getting inode number allocated. + The MSDOS filesystems is playing a nice game to fake inode + number, so why not use it. + + The absence of inode number compatible with those allocated + for ordinary files was causing major trouble with hard link + in particular and other parts of the kernel I guess. + */ + int ret = umsdos_create_any (dir,dentry,mode,rdev,0); + dput(dentry); + return ret; } /* - Remove a sub-directory. + Remove a sub-directory. */ int UMSDOS_rmdir( struct inode * dir, - const char * name, - int len) + struct dentry *dentry) { - /* #Specification: style / iput strategy - In the UMSDOS project, I am trying to apply a single - programming style regarding inode management. Many - entry point are receiving an inode to act on, and must - do an iput() as soon as they are finished with - the inode. - - For simple case, there is no problem. When you introduce - error checking, you end up with many iput placed around the - code. - - The coding style I use all around is one where I am trying - to provide independent flow logic (I don't know how to - name this). With this style, code is easier to understand - but you rapidly get iput() all around. Here is an exemple - of what I am trying to avoid. - - # - if (a){ - ... - if(b){ - ... - } - ... - if (c){ - // Complex state. Was b true ? - ... - } - ... - } - // Weird state - if (d){ - // ... - } - // Was iput finally done ? - return status; - # - - Here is the style I am using. Still sometime I do the - first when things are very simple (or very complicated :-( ) - - # - if (a){ - if (b){ - ... - }else if (c){ - // A single state gets here - } - }else if (d){ - ... - } - return status; - # - - Again, while this help clarifying the code, I often get a lot - of iput(), unlike the first style, where I can place few - "strategic" iput(). "strategic" also mean, more difficult - to place. - - So here is the style I will be using from now on in this project. - There is always an iput() at the end of a function (which has - to do an iput()). One iput by inode. There is also one iput() - at the places where a successful operation is achieved. This - iput() is often done by a sub-function (often from the msdos - file system). So I get one too many iput() ? At the place - where an iput() is done, the inode is simply nulled, disabling - the last one. - - # - if (a){ - if (b){ - ... - }else if (c){ - msdos_rmdir(dir,...); - dir = NULL; - } - }else if (d){ - ... - } - iput (dir); - return status; - # - - Note that the umsdos_lockcreate() and umsdos_unlockcreate() function - pair goes against this practice of "forgetting" the inode as soon - as possible. - */ - int ret = umsdos_nevercreat(dir,name,len,-EPERM); - if (ret == 0){ - struct inode *sdir; - atomic_inc(&dir->i_count); - ret = UMSDOS_lookup (dir,name,len,&sdir); - PRINTK (("rmdir lookup %d ",ret)); - if (ret == 0){ - int empty; - umsdos_lockcreate(dir); - if (atomic_read(&sdir->i_count) > 1){ - ret = -EBUSY; - }else if ((empty = umsdos_isempty (sdir)) != 0){ - PRINTK (("isempty %d i_count %d ",empty, - atomic_read(&sdir->i_count))); + /* #Specification: style / iput strategy + In the UMSDOS project, I am trying to apply a single + programming style regarding inode management. Many + entry point are receiving an inode to act on, and must + do an iput() as soon as they are finished with + the inode. + + For simple case, there is no problem. When you introduce + error checking, you end up with many iput placed around the + code. + + The coding style I use all around is one where I am trying + to provide independent flow logic (I don't know how to + name this). With this style, code is easier to understand + but you rapidly get iput() all around. Here is an exemple + of what I am trying to avoid. + + # + if (a){ + ... + if(b){ + ... + } + ... + if (c){ + // Complex state. Was b true ? + ... + } + ... + } + // Weird state + if (d){ + // ... + } + // Was iput finally done ? + return status; + # + + Here is the style I am using. Still sometime I do the + first when things are very simple (or very complicated :-( ) + + # + if (a){ + if (b){ + ... + }else if (c){ + // A single state gets here + } + }else if (d){ + ... + } + return status; + # + + Again, while this help clarifying the code, I often get a lot + of iput(), unlike the first style, where I can place few + "strategic" iput(). "strategic" also mean, more difficult + to place. + + So here is the style I will be using from now on in this project. + There is always an iput() at the end of a function (which has + to do an iput()). One iput by inode. There is also one iput() + at the places where a successful operation is achieved. This + iput() is often done by a sub-function (often from the msdos + file system). So I get one too many iput() ? At the place + where an iput() is done, the inode is simply nulled, disabling + the last one. + + # + if (a){ + if (b){ + ... + }else if (c){ + msdos_rmdir(dir,...); + dir = NULL; + } + }else if (d){ + ... + } + iput (dir); + return status; + # + + Note that the umsdos_lockcreate() and umsdos_unlockcreate() function + pair goes against this practice of "forgetting" the inode as soon + as possible. + */ + + int ret = umsdos_nevercreat(dir,dentry,-EPERM); + if (ret == 0){ + volatile struct inode *sdir; + dir->i_count++; + ret = UMSDOS_lookup (dir, dentry); + sdir = dentry->d_inode; + Printk (("rmdir lookup %d ",ret)); + if (ret == 0){ + int empty; + umsdos_lockcreate(dir); + if (sdir->i_count > 1){ + ret = -EBUSY; + }else if ((empty = umsdos_isempty (sdir)) != 0){ + struct dentry *tdentry; + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_FILE, NULL); + Printk (("isempty %d i_count %d ",empty,sdir->i_count)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || - current->fsuid == sdir->i_uid || - current->fsuid == dir->i_uid || - fsuser()) { - if (empty == 1){ - /* We have to removed the EMD file */ - ret = msdos_unlink(sdir,UMSDOS_EMD_FILE - ,UMSDOS_EMD_NAMELEN); - sdir = NULL; - } - /* sdir must be free before msdos_rmdir() */ - iput (sdir); - sdir = NULL; - PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink)); - if (ret == 0){ - struct umsdos_info info; - atomic_inc(&dir->i_count); - umsdos_parse (name,len,&info); - /* The findentry is there only to complete */ - /* the mangling */ - umsdos_findentry (dir,&info,2); - ret = msdos_rmdir (dir,info.fake.fname - ,info.fake.len); - if (ret == 0){ - ret = umsdos_delentry (dir,&info,1); - } - } - }else{ - /* sticky bit set and we don't have permission */ - PRINTK(("sticky set ")); - ret = -EPERM; - } - }else{ - /* - The subdirectory is not empty, so leave it there - */ - ret = -ENOTEMPTY; - } - iput(sdir); - umsdos_unlockcreate(dir); - } + if ( !(dir->i_mode & S_ISVTX) || fsuser() || + current->fsuid == sdir->i_uid || + current->fsuid == dir->i_uid ) { + if (empty == 1){ + /* We have to removed the EMD file */ + ret = msdos_unlink (sdir, tdentry); + sdir = NULL; + } + /* sdir must be free before msdos_rmdir() */ + /* iput (sdir); FIXME */ + sdir = NULL; + Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink)); + if (ret == 0){ + struct umsdos_info info; + struct dentry *temp; + dir->i_count++; + umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); + /* The findentry is there only to complete */ + /* the mangling */ + umsdos_findentry (dir,&info,2); + temp = creat_dentry (info.fake.fname, info.fake.len, NULL); + + ret = msdos_rmdir (dir, temp); + if (ret == 0){ + ret = umsdos_delentry (dir,&info,1); + } + } + }else{ + /* sticky bit set and we don't have permission */ + Printk(("sticky set ")); + ret = -EPERM; } - iput (dir); - PRINTK (("umsdos_rmdir %d\n",ret)); - return ret; + }else{ + /* + The subdirectory is not empty, so leave it there + */ + ret = -ENOTEMPTY; + } + /* iput(sdir); FIXME */ + umsdos_unlockcreate(dir); + } + } + dput(dentry); + Printk (("umsdos_rmdir %d\n",ret)); + return ret; } + + + /* - Remove a file from the directory. + Remove a file from the directory. */ int UMSDOS_unlink ( struct inode * dir, - const char * name, - int len) + struct dentry *dentry) { - int ret = umsdos_nevercreat(dir,name,len,-EPERM); - if (ret == 0){ - struct umsdos_info info; - ret = umsdos_parse (name,len,&info); - if (ret == 0){ - umsdos_lockcreate(dir); - ret = umsdos_findentry(dir,&info,1); - if (ret == 0){ - PRINTK (("UMSDOS_unlink %s ",info.fake.fname)); + int ret = umsdos_nevercreat(dir,dentry,-EPERM); + if (ret == 0){ + struct umsdos_info info; + ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); + if (ret == 0){ + umsdos_lockcreate(dir); + ret = umsdos_findentry(dir,&info,1); + if (ret == 0){ + Printk (("UMSDOS_unlink %s ",info.fake.fname)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || - current->fsuid == info.entry.uid || - current->fsuid == dir->i_uid || - fsuser()) { - if (info.entry.flags & UMSDOS_HLINK){ - /* #Specification: hard link / deleting a link - When we deletes a file, and this file is a link - we must subtract 1 to the nlink field of the - hidden link. - - If the count goes to 0, we delete this hidden - link too. - */ - /* - First, get the inode of the hidden link - using the standard lookup function. - */ - struct inode *inode; - atomic_inc(&dir->i_count); - ret = UMSDOS_lookup (dir,name,len,&inode); - if (ret == 0){ - PRINTK (("unlink nlink = %d ",inode->i_nlink)); - inode->i_nlink--; - if (inode->i_nlink == 0){ - struct inode *hdir = iget(inode->i_sb - ,inode->u.umsdos_i.i_dir_owner); - struct umsdos_dirent entry; - ret = umsdos_inode2entry (hdir,inode,&entry); - if (ret == 0){ - ret = UMSDOS_unlink (hdir,entry.name - ,entry.name_len); - }else{ - iput (hdir); - } - }else{ - struct iattr newattrs; - newattrs.ia_valid = 0; - ret = UMSDOS_notify_change (inode, &newattrs); - } - iput (inode); - } - } - if (ret == 0){ - ret = umsdos_delentry (dir,&info,0); - if (ret == 0){ - PRINTK (("Avant msdos_unlink %s ",info.fake.fname)); - atomic_inc(&dir->i_count); - ret = msdos_unlink_umsdos (dir,info.fake.fname - ,info.fake.len); - PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname - ,info.entry.mode,ret)); - } - } - }else{ - /* sticky bit set and we've not got permission */ - PRINTK(("sticky set ")); - ret = -EPERM; - } - } - umsdos_unlockcreate(dir); + if ( !(dir->i_mode & S_ISVTX) || fsuser() || + current->fsuid == info.entry.uid || + current->fsuid == dir->i_uid ) { + if (info.entry.flags & UMSDOS_HLINK){ + /* #Specification: hard link / deleting a link + When we deletes a file, and this file is a link + we must subtract 1 to the nlink field of the + hidden link. + + If the count goes to 0, we delete this hidden + link too. + */ + /* + First, get the inode of the hidden link + using the standard lookup function. + */ + struct inode *inode; + dir->i_count++; + ret = UMSDOS_lookup (dir,dentry); + inode = dentry->d_inode; + if (ret == 0){ + Printk (("unlink nlink = %d ",inode->i_nlink)); + inode->i_nlink--; + if (inode->i_nlink == 0){ + struct inode *hdir = iget(inode->i_sb + ,inode->u.umsdos_i.i_dir_owner); + struct umsdos_dirent entry; + ret = umsdos_inode2entry (hdir,inode,&entry); + if (ret == 0){ + ret = UMSDOS_unlink (hdir,dentry); + }else{ + /* iput (hdir); FIXME */ } - } - iput (dir); - PRINTK (("umsdos_unlink %d\n",ret)); - return ret; + }else{ + struct iattr newattrs; + newattrs.ia_valid = 0; + ret = UMSDOS_notify_change (dentry, &newattrs); + } + /* iput (inode); FIXME */ + } + } + if (ret == 0){ + ret = umsdos_delentry (dir,&info,0); + if (ret == 0){ + struct dentry *temp; + Printk (("Avant msdos_unlink %s ",info.fake.fname)); + dir->i_count++; + temp = creat_dentry (info.fake.fname, info.fake.len, NULL); + ret = msdos_unlink_umsdos (dir, temp); + Printk (("msdos_unlink %s %o ret %d ",info.fake.fname + ,info.entry.mode,ret)); + } + } + }else{ + /* sticky bit set and we've not got permission */ + Printk(("sticky set ")); + ret = -EPERM; + } + } + umsdos_unlockcreate(dir); + } + } + dput(dentry); + Printk (("umsdos_unlink %d\n",ret)); + return ret; } + + /* Rename a file (move) in the file system. */ int UMSDOS_rename( - struct inode * old_dir, - const char * old_name, - int old_len, - struct inode * new_dir, - const char * new_name, - int new_len) + struct inode * old_dir, + struct dentry * old_dentry, + struct inode * new_dir, + struct dentry * new_dentry) { - /* #Specification: weakness / rename - There is a case where UMSDOS rename has a different behavior - than normal UNIX file system. Renaming an open file across - directory boundary does not work. Renaming an open file within - a directory does work however. - - The problem (not sure) is in the linux VFS msdos driver. - I believe this is not a bug but a design feature, because - an inode number represent some sort of directory address - in the MSDOS directory structure. So moving the file into - another directory does not preserve the inode number. - */ - int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST); - if (ret == 0){ - /* umsdos_rename_f eat the inode and we may need those later */ - atomic_inc(&old_dir->i_count); - atomic_inc(&new_dir->i_count); - ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name - ,new_len,0); - if (ret == -EEXIST){ - /* #Specification: rename / new name exist - If the destination name already exist, it will - silently be removed. EXT2 does it this way - and this is the spec of SUNOS. So does UMSDOS. - - If the destination is an empty directory it will - also be removed. - */ - /* #Specification: rename / new name exist / possible flaw - The code to handle the deletion of the target (file - and directory) use to be in umsdos_rename_f, surrounded - by proper directory locking. This was insuring that only - one process could achieve a rename (modification) operation - in the source and destination directory. This was also - insuring the operation was "atomic". - - This has been changed because this was creating a kernel - stack overflow (stack is only 4k in the kernel). To avoid - the code doing the deletion of the target (if exist) has - been moved to a upper layer. umsdos_rename_f is tried - once and if it fails with EEXIST, the target is removed - and umsdos_rename_f is done again. - - This makes the code cleaner and (not sure) solve a - deadlock problem one tester was experiencing. - - The point is to mention that possibly, the semantic of - "rename" may be wrong. Anyone dare to check that :-) - Be aware that IF it is wrong, to produce the problem you - will need two process trying to rename a file to the - same target at the same time. Again, I am not sure it - is a problem at all. - */ - /* This is not super efficient but should work */ - atomic_inc(&new_dir->i_count); - ret = UMSDOS_unlink (new_dir,new_name,new_len); -chkstk(); - PRINTK (("rename unlink ret %d %d -- ",ret,new_len)); - if (ret == -EISDIR){ - atomic_inc(&new_dir->i_count); - ret = UMSDOS_rmdir (new_dir,new_name,new_len); -chkstk(); - PRINTK (("rename rmdir ret %d -- ",ret)); - } - if (ret == 0){ - ret = umsdos_rename_f (old_dir,old_name,old_len - ,new_dir,new_name,new_len,0); - new_dir = old_dir = NULL; - } - } - } - iput (new_dir); - iput (old_dir); - return ret; + /* #Specification: weakness / rename + There is a case where UMSDOS rename has a different behavior + than normal UNIX file system. Renaming an open file across + directory boundary does not work. Renaming an open file within + a directory does work however. + + The problem (not sure) is in the linux VFS msdos driver. + I believe this is not a bug but a design feature, because + an inode number represent some sort of directory address + in the MSDOS directory structure. So moving the file into + another directory does not preserve the inode number. + */ + int ret = umsdos_nevercreat(new_dir,new_dentry,-EEXIST); + if (ret == 0){ + /* umsdos_rename_f eat the inode and we may need those later */ + old_dir->i_count++; + new_dir->i_count++; + ret = umsdos_rename_f (old_dir,old_dentry,new_dir,new_dentry,0); + if (ret == -EEXIST){ + /* #Specification: rename / new name exist + If the destination name already exist, it will + silently be removed. EXT2 does it this way + and this is the spec of SUNOS. So does UMSDOS. + + If the destination is an empty directory it will + also be removed. + */ + /* #Specification: rename / new name exist / possible flaw + The code to handle the deletion of the target (file + and directory) use to be in umsdos_rename_f, surrounded + by proper directory locking. This was insuring that only + one process could achieve a rename (modification) operation + in the source and destination directory. This was also + insuring the operation was "atomic". + + This has been changed because this was creating a kernel + stack overflow (stack is only 4k in the kernel). To avoid + the code doing the deletion of the target (if exist) has + been moved to a upper layer. umsdos_rename_f is tried + once and if it fails with EEXIST, the target is removed + and umsdos_rename_f is done again. + + This makes the code cleaner and (not sure) solve a + deadlock problem one tester was experiencing. + + The point is to mention that possibly, the semantic of + "rename" may be wrong. Anyone dare to check that :-) + Be aware that IF it is wrong, to produce the problem you + will need two process trying to rename a file to the + same target at the same time. Again, I am not sure it + is a problem at all. + */ + /* This is not super efficient but should work */ + new_dir->i_count++; + ret = UMSDOS_unlink (new_dir,new_dentry); + chkstk(); + Printk (("rename unlink ret %d -- ",ret)); + if (ret == -EISDIR){ + new_dir->i_count++; + ret = UMSDOS_rmdir (new_dir,new_dentry); + chkstk(); + Printk (("rename rmdir ret %d -- ",ret)); + } + if (ret == 0){ + ret = umsdos_rename_f(old_dir,old_dentry, + new_dir,new_dentry,0); + new_dir = old_dir = NULL; + } + } + } + dput (new_dentry); + dput (old_dentry); + return ret; } diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.1.86/linux/fs/umsdos/rdir.c Mon Jun 16 16:35:59 1997 +++ linux/fs/umsdos/rdir.c Thu Feb 12 13:36:57 1998 @@ -32,240 +32,270 @@ static int rdir_filldir( void * buf, - const char * name, + const char *name, int name_len, off_t offset, ino_t ino) { - int ret = 0; - struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf; - if (d->real_root){ - /* real root of a pseudo_rooted partition */ - if (name_len != UMSDOS_PSDROOT_LEN - || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){ - /* So it is not the /linux directory */ - if (name_len == 2 - && name[0] == '.' - && name[1] == '.'){ + int ret = 0; + struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf; + Printk ((KERN_DEBUG "rdir_filldir /mn/: entering\n")); + if (d->real_root){ + Printk ((KERN_DEBUG "rdir_filldir /mn/: real root!\n")); + /* real root of a pseudo_rooted partition */ + if (name_len != UMSDOS_PSDROOT_LEN + || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){ + /* So it is not the /linux directory */ + if (name_len == 2 + && name[0] == '.' + && name[1] == '.'){ /* Make sure the .. entry points back to the pseudo_root */ - ino = pseudo_root->i_ino; - } - ret = d->filldir (d->dirbuf,name,name_len,offset,ino); - } - }else{ - /* Any DOS directory */ - ret = d->filldir (d->dirbuf,name,name_len,offset,ino); - } - return ret; + ino = pseudo_root->i_ino; + } + ret = d->filldir (d->dirbuf,name,name_len,offset,ino); + } + }else{ + /* Any DOS directory */ + Printk ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %12s (%d)\n",d->filldir,name,ino)); + ret = d->filldir (d->dirbuf,name,name_len,offset,ino); + } + return ret; } static int UMSDOS_rreaddir ( - struct inode *dir, struct file *filp, - void *dirbuf, + void *dirbuf, filldir_t filldir) { - struct RDIR_FILLDIR bufk; - bufk.filldir = filldir; - bufk.dirbuf = dirbuf; - bufk.real_root = pseudo_root != NULL - && dir == dir->i_sb->s_mounted - && dir == pseudo_root->i_sb->s_mounted; - return fat_readdir(dir,filp,&bufk,rdir_filldir); + struct RDIR_FILLDIR bufk; + struct inode *dir = filp->f_dentry->d_inode; + + Printk ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf)); + + + bufk.filldir = filldir; + bufk.dirbuf = dirbuf; + bufk.real_root = pseudo_root + && dir == iget(dir->i_sb,UMSDOS_ROOT_INO) + && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO); + Printk ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n",filldir)); + return fat_readdir(filp, &bufk, rdir_filldir); } + /* - Lookup into a non promoted directory. - If the result is a directory, make sure we find out if it is - a promoted one or not (calling umsdos_setup_dir_inode(inode)). + Lookup into a non promoted directory. + If the result is a directory, make sure we find out if it is + a promoted one or not (calling umsdos_setup_dir_inode(inode)). */ int umsdos_rlookup_x( - struct inode *dir, - const char *name, - int len, - struct inode **result, /* Will hold inode of the file, if successful */ - int nopseudo) /* Don't care about pseudo root mode */ - /* so locating "linux" will work */ + struct inode *dir, + struct dentry *dentry, + int nopseudo) /* Don't care about pseudo root mode */ + /* so locating "linux" will work */ { - int ret; - if (pseudo_root != NULL - && len == 2 - && name[0] == '.' - && name[1] == '.' - && dir == dir->i_sb->s_mounted - && dir == pseudo_root->i_sb->s_mounted){ - *result = pseudo_root; - atomic_inc(&pseudo_root->i_count); - ret = 0; - /* #Specification: pseudo root / DOS/.. - In the real root directory (c:\), the directory .. - is the pseudo root (c:\linux). - */ - }else{ - ret = umsdos_real_lookup (dir,name,len,result); - if (ret == 0){ - struct inode *inode = *result; - if (inode == pseudo_root && !nopseudo){ - /* #Specification: pseudo root / DOS/linux - Even in the real root directory (c:\), the directory - /linux won't show - */ - ret = -ENOENT; - iput (pseudo_root); - *result = NULL; - }else if (S_ISDIR(inode->i_mode)){ - /* We must place the proper function table */ - /* depending if this is a MsDOS directory or an UMSDOS directory */ - umsdos_setup_dir_inode(inode); - } - } - } - iput (dir); - return ret; + int len = dentry->d_name.len; + const char *name = dentry->d_name.name; + struct inode *inode; + int ret; + if (pseudo_root + && len == 2 + && name[0] == '.' + && name[1] == '.' + && dir == iget(dir->i_sb,UMSDOS_ROOT_INO) + && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO) ){ + /* *result = pseudo_root;*/ + Printk (("umsdos_rlookup_x: we are at pseudo-root thingy?\n")); + pseudo_root->i_count++; + ret = 0; + /* #Specification: pseudo root / DOS/.. + In the real root directory (c:\), the directory .. + is the pseudo root (c:\linux). + */ + }else{ + ret = umsdos_real_lookup (dir, dentry); inode=dentry->d_inode; + Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %s in %d returned %d\n", name, dir->i_ino, ret)); + Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode)); + if (inode) { /* /mn/ FIXME: DEL_ME */ + Printk ((KERN_DEBUG "i_ino=%d\n",inode->i_ino)); + } else { + Printk ((KERN_DEBUG "NONE!\n")); + } + if ((ret == 0) && inode){ + + if (pseudo_root && inode == pseudo_root && !nopseudo){ + /* #Specification: pseudo root / DOS/linux + Even in the real root directory (c:\), the directory + /linux won't show + */ + Printk (("umsdos_rlookup_x: do the pseudo-thingy...\n")); + ret = -ENOENT; + iput (pseudo_root); + + }else if (S_ISDIR(inode->i_mode)){ + /* We must place the proper function table */ + /* depending if this is a MsDOS directory or an UMSDOS directory */ + Printk (("umsdos_rlookup_x: setting up setup_dir_inode %d...\n", inode->i_ino)); + umsdos_setup_dir_inode (inode); + } + } + } + iput (dir); + Printk ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); + return ret; } + + int UMSDOS_rlookup( struct inode *dir, - const char *name, - int len, - struct inode **result) /* Will hold inode of the file, if successful */ + struct dentry *dentry + ) { - return umsdos_rlookup_x(dir,name,len,result,0); + Printk ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%d in %20s\n",dir->i_ino,dentry->d_name.name)); + return umsdos_rlookup_x(dir,dentry,0); } + static int UMSDOS_rrmdir ( struct inode *dir, - const char *name, - int len) + struct dentry *dentry) { - /* #Specification: dual mode / rmdir in a DOS directory - In a DOS (not EMD in it) directory, we use a reverse strategy - compared with an Umsdos directory. We assume that a subdirectory - of a DOS directory is also a DOS directory. This is not always - true (umssync may be used anywhere), but make sense. - - So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY - then we check if it is a Umsdos directory. We check if it is - really empty (only . .. and --linux-.--- in it). If it is true - we remove the EMD and do a msdos_rmdir() again. - - In a Umsdos directory, we assume all subdirectory are also - Umsdos directory, so we check the EMD file first. - */ - int ret; - if (umsdos_is_pseudodos(dir,name,len)){ - /* #Specification: pseudo root / rmdir /DOS - The pseudo sub-directory /DOS can't be removed! - This is done even if the pseudo root is not a Umsdos - directory anymore (very unlikely), but an accident (under - MsDOS) is always possible. - - EPERM is returned. - */ - ret = -EPERM; + /* #Specification: dual mode / rmdir in a DOS directory + In a DOS (not EMD in it) directory, we use a reverse strategy + compared with an Umsdos directory. We assume that a subdirectory + of a DOS directory is also a DOS directory. This is not always + true (umssync may be used anywhere), but make sense. + + So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY + then we check if it is a Umsdos directory. We check if it is + really empty (only . .. and --linux-.--- in it). If it is true + we remove the EMD and do a msdos_rmdir() again. + + In a Umsdos directory, we assume all subdirectory are also + Umsdos directory, so we check the EMD file first. + */ + int ret; + if (umsdos_is_pseudodos(dir,dentry)){ + /* #Specification: pseudo root / rmdir /DOS + The pseudo sub-directory /DOS can't be removed! + This is done even if the pseudo root is not a Umsdos + directory anymore (very unlikely), but an accident (under + MsDOS) is always possible. + + EPERM is returned. + */ + ret = -EPERM; + }else{ + umsdos_lockcreate (dir); + dir->i_count++; + ret = msdos_rmdir (dir,dentry); + if (ret == -ENOTEMPTY){ + struct inode *sdir; + dir->i_count++; + + ret = UMSDOS_rlookup (dir,dentry); + sdir = dentry->d_inode; + PRINTK (("rrmdir lookup %d ",ret)); + if (ret == 0){ + int empty; + if ((empty = umsdos_isempty (sdir)) != 0){ + PRINTK (("isempty %d i_count %d ",empty, + atomic_read(&sdir->i_count))); + if (empty == 2){ + /* + Not a Umsdos directory, so the previous msdos_rmdir + was not lying :-) + */ + ret = -ENOTEMPTY; + }else if (empty == 1){ + /* We have to removed the EMD file */ + struct dentry *temp; + temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); + ret = msdos_unlink(sdir, temp); + sdir = NULL; + if (ret == 0){ + dir->i_count++; + ret = msdos_rmdir (dir,dentry); + } + } }else{ - umsdos_lockcreate (dir); - atomic_inc(&dir->i_count); - ret = msdos_rmdir (dir,name,len); - if (ret == -ENOTEMPTY){ - struct inode *sdir; - atomic_inc(&dir->i_count); - ret = UMSDOS_rlookup (dir,name,len,&sdir); - PRINTK (("rrmdir lookup %d ",ret)); - if (ret == 0){ - int empty; - if ((empty = umsdos_isempty (sdir)) != 0){ - PRINTK (("isempty %d i_count %d ",empty, - atomic_read(&sdir->i_count))); - if (empty == 2){ - /* - Not a Umsdos directory, so the previous msdos_rmdir - was not lying :-) - */ - ret = -ENOTEMPTY; - }else if (empty == 1){ - /* We have to removed the EMD file */ - ret = msdos_unlink(sdir,UMSDOS_EMD_FILE - ,UMSDOS_EMD_NAMELEN); - sdir = NULL; - if (ret == 0){ - atomic_inc(&dir->i_count); - ret = msdos_rmdir (dir,name,len); - } - } - }else{ - ret = -ENOTEMPTY; - } - iput (sdir); - } - } - umsdos_unlockcreate (dir); + ret = -ENOTEMPTY; } - iput (dir); - return ret; + iput (sdir); + } + } + umsdos_unlockcreate (dir); + } + iput (dir); + return ret; } /* #Specification: dual mode / introduction - One goal of UMSDOS is to allow a practical and simple coexistence - between MsDOS and Linux in a single partition. Using the EMD file - in each directory, UMSDOS add Unix semantics and capabilities to - normal DOS file system. To help and simplify coexistence, here is - the logic related to the EMD file. - - If it is missing, then the directory is managed by the MsDOS driver. - The names are limited to DOS limits (8.3). No links, no device special - and pipe and so on. - - If it is there, it is the directory. If it is there but empty, then - the directory looks empty. The utility umssync allows synchronisation - of the real DOS directory and the EMD. - - Whenever umssync is applied to a directory without EMD, one is - created on the fly. The directory is promoted to full unix semantic. - Of course, the ls command will show exactly the same content as before - the umssync session. - - It is believed that the user/admin will promote directories to unix - semantic as needed. - - The strategy to implement this is to use two function table (struct - inode_operations). One for true UMSDOS directory and one for directory - with missing EMD. - - Functions related to the DOS semantic (but aware of UMSDOS) generally - have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate - from the one with full UMSDOS semantic. + One goal of UMSDOS is to allow a practical and simple coexistence + between MsDOS and Linux in a single partition. Using the EMD file + in each directory, UMSDOS add Unix semantics and capabilities to + normal DOS file system. To help and simplify coexistence, here is + the logic related to the EMD file. + + If it is missing, then the directory is managed by the MsDOS driver. + The names are limited to DOS limits (8.3). No links, no device special + and pipe and so on. + + If it is there, it is the directory. If it is there but empty, then + the directory looks empty. The utility umssync allows synchronisation + of the real DOS directory and the EMD. + + Whenever umssync is applied to a directory without EMD, one is + created on the fly. The directory is promoted to full unix semantic. + Of course, the ls command will show exactly the same content as before + the umssync session. + + It is believed that the user/admin will promote directories to unix + semantic as needed. + + The strategy to implement this is to use two function table (struct + inode_operations). One for true UMSDOS directory and one for directory + with missing EMD. + + Functions related to the DOS semantic (but aware of UMSDOS) generally + have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate + from the one with full UMSDOS semantic. */ static struct file_operations umsdos_rdir_operations = { - NULL, /* lseek - default */ - UMSDOS_dir_read, /* read */ - NULL, /* write - bad */ - UMSDOS_rreaddir, /* readdir */ - NULL, /* poll - default */ - UMSDOS_ioctl_dir, /* ioctl - default */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - NULL /* fsync */ + NULL, /* lseek - default */ + UMSDOS_dir_read, /* read */ + NULL, /* write - bad */ + UMSDOS_rreaddir, /* readdir */ + NULL, /* poll - default */ + UMSDOS_ioctl_dir, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ }; struct inode_operations umsdos_rdir_inode_operations = { - &umsdos_rdir_operations, /* default directory file-ops */ - msdos_create, /* create */ - UMSDOS_rlookup, /* lookup */ - NULL, /* link */ - msdos_unlink, /* unlink */ - NULL, /* symlink */ - msdos_mkdir, /* mkdir */ - UMSDOS_rrmdir, /* rmdir */ - NULL, /* mknod */ - msdos_rename, /* rename */ - NULL, /* readlink */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ + &umsdos_rdir_operations, /* default directory file-ops */ + msdos_create, /* create */ + UMSDOS_rlookup, /* lookup */ + NULL, /* link */ + msdos_unlink, /* unlink */ + NULL, /* symlink */ + msdos_mkdir, /* mkdir */ + UMSDOS_rrmdir, /* rmdir */ + NULL, /* mknod */ + msdos_rename, /* rename */ + NULL, /* readlink */ + NULL, /* followlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL, /* revalidate */ }; diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c --- v2.1.86/linux/fs/umsdos/symlink.c Mon Jun 16 16:35:59 1997 +++ linux/fs/umsdos/symlink.c Thu Feb 12 13:36:57 1998 @@ -22,38 +22,99 @@ #define PRINTK(x) #define Printk(x) printk x +static struct file_operations umsdos_symlink_operations; + + /* Read the data associate with the symlink. Return length read in buffer or a negative error code. + FIXME, this is messed up. + + /mn/ WIP fixing... */ static int umsdos_readlink_x ( - struct inode *inode, + struct dentry *dentry, char *buffer, - long (*msdos_read)(struct inode *, struct file *, char *, unsigned long), int bufsiz) { - int ret = inode->i_size; + int ret = dentry->d_inode->i_size; + loff_t loffs = 0; struct file filp; + + memset (&filp, 0, sizeof (filp)); + filp.f_pos = 0; filp.f_reada = 0; + filp.f_flags = O_RDONLY; + filp.f_dentry = dentry; + filp.f_op = &umsdos_symlink_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + if (ret > bufsiz) ret = bufsiz; - if ((*msdos_read) (inode, &filp, buffer,ret) != ret){ + + Printk ((KERN_WARNING "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%ld, offs=%d\n", &filp, buffer, ret, loffs)); + Printk ((KERN_WARNING " f_op=%p\n", filp.f_op)); + Printk ((KERN_WARNING " inode=%d, i_size=%d\n", filp.f_dentry->d_inode->i_ino,filp.f_dentry->d_inode->i_size)); + Printk ((KERN_WARNING " f_pos=%ld\n", filp.f_pos)); + Printk ((KERN_WARNING " name=%12s\n", filp.f_dentry->d_name.name)); + Printk ((KERN_WARNING " i_binary(sb)=%d\n", MSDOS_I(filp.f_dentry->d_inode)->i_binary )); + Printk ((KERN_WARNING " f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags)); + Printk ((KERN_WARNING " f_owner=%d\n", filp.f_owner)); + Printk ((KERN_WARNING " f_version=%ld\n", filp.f_version)); + Printk ((KERN_WARNING " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin)); + + + /* FIXME */ + Printk (("umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %ld)\n", &filp, buffer, ret, loffs)); + if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret){ ret = -EIO; } +#if 0 + { + struct umsdos_dirent *mydirent=buffer; + + Printk ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); + Printk ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); + Printk ((KERN_DEBUG " (DDD) name=>%20s<\n",mydirent->name)); + } +#endif + + Printk (("umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%ld ret=%d\n", loffs, ret)); return ret; } -static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen) + + +static int UMSDOS_readlink(struct dentry *dentry, char *buffer, int buflen) { int ret; - ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen); - PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen)); - iput(inode); + Printk (("UMSDOS_readlink: calling umsdos_readlink_x for %20s\n", dentry->d_name.name)); + ret = umsdos_readlink_x (dentry, buffer, buflen); + Printk (("readlink %d bufsiz %d\n", ret, buflen)); + /* dput(dentry); / * FIXME /mn/ */ + Printk (("UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret)); return ret; } +static struct dentry *UMSDOS_followlink(struct dentry * dentry, struct dentry * base) +{ + int ret; + char symname[256]; + struct inode *inode = dentry->d_inode; + mm_segment_t old_fs = get_fs(); + Printk ((KERN_ERR "UMSDOS_followlink /mn/: (%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name)); + + set_fs (KERNEL_DS); /* we read into kernel space */ + ret = umsdos_readlink_x (dentry, &symname, 256); + set_fs (old_fs); + + base = creat_dentry (symname, ret, NULL); +/* UMSDOS_lookup (dentry->d_parent->d_inode, base);*/ + + return base; +} + static struct file_operations umsdos_symlink_operations = { NULL, /* lseek - default */ NULL, /* read */ @@ -67,8 +128,9 @@ NULL /* fsync */ }; + struct inode_operations umsdos_symlink_inode_operations = { - &umsdos_symlink_operations, /* default file operations */ + NULL, /* default file operations */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ @@ -79,11 +141,16 @@ NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ - NULL, /* readpage */ + NULL/*UMSDOS_followlink*/, /* followlink */ /* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */ + generic_readpage, /* readpage */ /* in original NULL. changed to generic_readpage. FIXME? /mn/ */ NULL, /* writepage */ - NULL, /* bmap */ + fat_bmap, /* bmap */ /* in original NULL. changed to fat_bmap. FIXME? /mn/ */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ + }; diff -u --recursive --new-file v2.1.86/linux/include/asm-alpha/fpu.h linux/include/asm-alpha/fpu.h --- v2.1.86/linux/include/asm-alpha/fpu.h Mon Jan 12 14:49:36 1998 +++ linux/include/asm-alpha/fpu.h Thu Feb 12 13:31:28 1998 @@ -81,7 +81,38 @@ return fp; } -extern unsigned long rdfpcr(void); -extern void wrfpcr(unsigned long); +#ifdef __KERNEL__ + +/* The following two functions don't need trapb/excb instructions + around the mf_fpcr/mt_fpcr instructions because (a) the kernel + never generates arithmetic faults and (b) call_pal instructions + are implied trap barriers. */ + +static inline unsigned long rdfpcr(void) +{ + unsigned long tmp, ret; + __asm__ ("stt $f0,%0\n\t" + "mf_fpcr $f0\n\t" + "stt $f0,%1\n\t" + "ldt $f0,%0" + : "=m"(tmp), "=m"(ret)); + return ret; +} + +static inline void wrfpcr(unsigned long val) +{ + unsigned long tmp; + __asm__ __volatile__ ( + "stt $f0,%0\n\t" + "ldt $f0,%1\n\t" + "mt_fpcr $f0\n\t" + "ldt $f0,%0" + : "=m"(tmp) : "m"(val)); +} + +extern unsigned long alpha_read_fp_reg (unsigned long reg); +extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); + +#endif /* __KERNEL__ */ #endif /* __ASM_ALPHA_FPU_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-alpha/ioctls.h linux/include/asm-alpha/ioctls.h --- v2.1.86/linux/include/asm-alpha/ioctls.h Thu Dec 4 13:09:01 1997 +++ linux/include/asm-alpha/ioctls.h Thu Feb 12 16:25:04 1998 @@ -86,6 +86,8 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -u --recursive --new-file v2.1.86/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.1.86/linux/include/asm-alpha/unistd.h Thu Feb 12 20:56:12 1998 +++ linux/include/asm-alpha/unistd.h Thu Feb 12 16:44:15 1998 @@ -240,7 +240,7 @@ #define __NR_bdflush 300 #define __NR_sethae 301 #define __NR_mount 302 -#define __NR_adjtimex 303 +#define __NR_old_adjtimex 303 #define __NR_swapoff 304 #define __NR_getdents 305 #define __NR_create_module 306 diff -u --recursive --new-file v2.1.86/linux/include/asm-arm/ioctls.h linux/include/asm-arm/ioctls.h --- v2.1.86/linux/include/asm-arm/ioctls.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/ioctls.h Thu Feb 12 16:25:04 1998 @@ -47,6 +47,8 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -u --recursive --new-file v2.1.86/linux/include/asm-i386/ioctls.h linux/include/asm-i386/ioctls.h --- v2.1.86/linux/include/asm-i386/ioctls.h Thu Dec 4 13:09:01 1997 +++ linux/include/asm-i386/ioctls.h Thu Feb 12 16:25:04 1998 @@ -47,6 +47,8 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h --- v2.1.86/linux/include/asm-m68k/amigahw.h Fri Dec 20 01:20:02 1996 +++ linux/include/asm-m68k/amigahw.h Thu Feb 12 16:30:13 1998 @@ -103,6 +103,7 @@ AMIGAHW_DECLARE(ALICE_PAL); /* PAL Alice (8374) */ AMIGAHW_DECLARE(ALICE_NTSC); /* NTSC Alice (8374) */ AMIGAHW_DECLARE(MAGIC_REKICK); /* A3000 Magic Hard Rekick */ + AMIGAHW_DECLARE(PCMCIA); /* PCMCIA Slot */ AMIGAHW_DECLARE(ZORRO); /* Zorro AutoConfig */ AMIGAHW_DECLARE(ZORRO3); /* Zorro III */ }; diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/amigamouse.h linux/include/asm-m68k/amigamouse.h --- v2.1.86/linux/include/asm-m68k/amigamouse.h Thu Feb 29 07:41:01 1996 +++ linux/include/asm-m68k/amigamouse.h Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -#ifndef _ASMm68k_AMIGAMOUSE_H -#define _ASMm68k_AMIGAMOUSE_H - -/* - * linux/include/asm-m68k/amigamouse.h: header file for Amiga Mouse driver - * by Michael Rausch - */ - -/* -#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT) -#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT) -*/ - -struct mouse_status { - unsigned char buttons; - unsigned char latch_buttons; - int dx; - int dy; - int present; - int ready; - int active; - struct wait_queue *wait; - struct fasync_struct *fasyncptr; -}; - -#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/amihdreg.h linux/include/asm-m68k/amihdreg.h --- v2.1.86/linux/include/asm-m68k/amihdreg.h Sun Mar 31 13:50:11 1996 +++ linux/include/asm-m68k/amihdreg.h Wed Dec 31 16:00:00 1969 @@ -1,31 +0,0 @@ -#ifndef _LINUX_AMIHDREG_H -#define _LINUX_AMIHDREG_H - -/* - * This file contains some defines for the Amiga IDE hd controller. - * Various sources. Check out some definitions (see comments with - * a ques). - */ - -#define IDE_DISABLE_IRQ 0x02 -#define IDE_ENABLE_IRQ 0x00 - -/* Bases of the hard drive controller */ -#define HD_BASE_A4000 0xdd2020 -#define HD_BASE_A1200 0xda0000 - -/* Offsets from one of the above bases */ -#define AMI_HD_ERROR (0x06) /* see err-bits */ -#define AMI_HD_NSECTOR (0x0a) /* nr of sectors to read/write */ -#define AMI_HD_SECTOR (0x0e) /* starting sector */ -#define AMI_HD_LCYL (0x12) /* starting cylinder */ -#define AMI_HD_HCYL (0x16) /* high byte of starting cyl */ -#define AMI_HD_SELECT (0x1a) /* 101dhhhh , d=drive, hhhh=head */ -#define AMI_HD_STATUS (0x1e) /* see status-bits */ -#define AMI_HD_CMD (0x101a) - -/* These are at different offsets from the base */ -#define HD_A4000_IRQ (0xdd3020) /* MSB = 1, Harddisk is source of interrupt */ -#define HD_A1200_IRQ (0xda9000) /* MSB = 1, Harddisk is source of interrupt */ - -#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/apollohw.h linux/include/asm-m68k/apollohw.h --- v2.1.86/linux/include/asm-m68k/apollohw.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/apollohw.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,71 @@ +/* apollohw.h : some structures to access apollo HW */ + +#ifndef _ASMm68k_APOLLOHW_H_ +#define _ASMm68k_APOLLOHW_H_ + + +/* + see scn2681 data sheet for more info. + member names are read_write. +*/ + +#define DECLARE_2681_FIELD(x) unsigned char x; unsigned char dummy##x + +struct SCN2681 { + + DECLARE_2681_FIELD(mra); + DECLARE_2681_FIELD(sra_csra); + DECLARE_2681_FIELD(BRGtest_cra); + DECLARE_2681_FIELD(rhra_thra); + DECLARE_2681_FIELD(ipcr_acr); + DECLARE_2681_FIELD(isr_imr); + DECLARE_2681_FIELD(ctu_ctur); + DECLARE_2681_FIELD(ctl_ctlr); + DECLARE_2681_FIELD(mrb); + DECLARE_2681_FIELD(srb_csrb); + DECLARE_2681_FIELD(tst_crb); + DECLARE_2681_FIELD(rhrb_thrb); + DECLARE_2681_FIELD(reserved); + DECLARE_2681_FIELD(ip_opcr); + DECLARE_2681_FIELD(startCnt_setOutBit); + DECLARE_2681_FIELD(stopCnt_resetOutBit); + +}; + +#if 0 +struct mc146818 { + + unsigned int second1:4, second2:4, alarm_second1:4, alarm_second2:4, + minute1:4, minute2:4, alarm_minute1:4, alarm_minute2:4; + unsigned int hours1:4, hours2:4, alarm_hours1:4, alarm_hours2:4, + day_of_week1:4, day_of_week2:4, day_of_month1:4, day_of_month2:4; + unsigned int month1:4, month2:4, year1:4, year2:4, :16; + +}; +#endif + +struct mc146818 { + unsigned char second, alarm_second; + unsigned char minute, alarm_minute; + unsigned char hours, alarm_hours; + unsigned char day_of_week, day_of_month; + unsigned char month, year; +}; + +#define IO_BASE 0x80000000 + +#define SIO01_PHYSADDR 0x10400 +#define SIO23_PHYSADDR 0x10500 +#define RTC_PHYSADDR 0x10900 +#define PICA 0x11000 +#define PICB 0x11100 +#define sio01 ((*(volatile struct SCN2681 *)(IO_BASE + SIO01_PHYSADDR))) +#define sio23 ((*(volatile struct SCN2681 *)(IO_BASE + SIO01_PHYSADDR))) +#define rtc (((volatile struct mc146818 *)(IO_BASE + RTC_PHYSADDR))) + +#define inb(addr) (*((volatile unsigned char *)(addr))) +#define outb(val,addr) (*((volatile unsigned char *)(addr)) = (val)) +#define inw(addr) (*((volatile unsigned short *)(addr))) +#define outw(val,addr) (*((volatile unsigned short *)(addr)) = (val)) + +#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atari_SCCserial.h linux/include/asm-m68k/atari_SCCserial.h --- v2.1.86/linux/include/asm-m68k/atari_SCCserial.h Wed May 15 23:05:11 1996 +++ linux/include/asm-m68k/atari_SCCserial.h Thu Feb 12 16:30:13 1998 @@ -28,6 +28,10 @@ #define SCC_BAUD_BASE_NONE 0 /* for not connected or unused * clock sources */ +#define SCC_BAUD_BASE_MVME_PCLK 781250 /* 12.5 MHz */ +#define SCC_BAUD_BASE_BVM 460800 /* 7.3728 MHz */ +#define SCC_BAUD_BASE_MVME 625000 /* 10.000 MHz */ + /* The SCC configuration structure */ struct atari_SCCserial { diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atari_rootsec.h linux/include/asm-m68k/atari_rootsec.h --- v2.1.86/linux/include/asm-m68k/atari_rootsec.h Wed Sep 25 00:47:41 1996 +++ linux/include/asm-m68k/atari_rootsec.h Wed Dec 31 16:00:00 1969 @@ -1,34 +0,0 @@ -#ifndef _LINUX_ATARI_ROOTSEC_H -#define _LINUX_ATARI_ROOTSEC_H - -/* - * linux/include/linux/atari_rootsec.h - * definitions for Atari Rootsector layout - * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) - * - * modified for ICD/Supra partitioning scheme restricted to at most 12 - * partitions - * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de) - */ - -struct partition_info -{ - u_char 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 */ -}; - -struct rootsector -{ - 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 */ - 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 */ -} __attribute__((__packed__)); - -#endif /* _LINUX_ATARI_ROOTSEC_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atari_stram.h linux/include/asm-m68k/atari_stram.h --- v2.1.86/linux/include/asm-m68k/atari_stram.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/atari_stram.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,17 @@ +#ifndef _M68K_ATARI_STRAM_H +#define _M68K_ATARI_STRAM_H + +/* + * Functions for Atari ST-RAM management + */ + +/* public interface */ +void *atari_stram_alloc( long size, unsigned long *start_mem, + const char *owner ); +void atari_stram_free( void *); + +/* functions called internally by other parts of the kernel */ +void atari_stram_init( void); +void atari_stram_reserve_pages( unsigned long start_mem ); + +#endif /*_M68K_ATARI_STRAM_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atarihdreg.h linux/include/asm-m68k/atarihdreg.h --- v2.1.86/linux/include/asm-m68k/atarihdreg.h Thu Apr 18 16:35:24 1996 +++ linux/include/asm-m68k/atarihdreg.h Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -#ifndef _LINUX_ATAHDREG_H -#define _LINUX_ATAHDREG_H - -/* - * This file contains some defines for the Falcon IDE hd controller. - * Various sources. Check out some definitions (see comments with - * a ques). - */ - -#define ATA_HD_BASE 0xfff00000 - -#define ATA_HD_DATA 0x00 /* _CTL when writing */ -#define ATA_HD_ERROR 0x05 /* see err-bits */ -#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */ -#define ATA_HD_SECTOR 0x0d /* starting sector */ -#define ATA_HD_LCYL 0x11 /* starting cylinder */ -#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */ -#define ATA_HD_CURRENT 0x19 /* 101dhhhh , d=drive, hhhh=head */ -#define ATA_HD_STATUS 0x1d /* see status-bits */ - -#define ATA_HD_CMD 0x39 -#define ATA_HD_ALTSTATUS 0x39 /* same as HD_STATUS but doesn't clear irq */ - -#endif /* _LINUX_ATAHDREG_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atarihw.h linux/include/asm-m68k/atarihw.h --- v2.1.86/linux/include/asm-m68k/atarihw.h Wed Apr 23 19:01:27 1997 +++ linux/include/asm-m68k/atarihw.h Thu Feb 12 16:30:13 1998 @@ -21,15 +21,38 @@ #define _LINUX_ATARIHW_H_ #include +#include extern u_long atari_mch_cookie; - -/* mch_cookie values (upper word) */ -#define ATARI_MCH_ST 0 -#define ATARI_MCH_STE 1 -#define ATARI_MCH_TT 2 -#define ATARI_MCH_FALCON 3 - +extern u_long atari_mch_type; +extern u_long atari_switches; +extern int atari_rtc_year_offset; +extern int atari_dont_touch_floppy_select; + +/* convenience macros for testing machine type */ +#define MACH_IS_ST ((atari_mch_cookie >> 16) == ATARI_MCH_ST) +#define MACH_IS_STE ((atari_mch_cookie >> 16) == ATARI_MCH_STE && \ + (atari_mch_cookie & 0xffff) == 0) +#define MACH_IS_MSTE ((atari_mch_cookie >> 16) == ATARI_MCH_STE && \ + (atari_mch_cookie & 0xffff) == 0x10) +#define MACH_IS_TT ((atari_mch_cookie >> 16) == ATARI_MCH_TT) +#define MACH_IS_FALCON ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON) +#define MACH_IS_MEDUSA (atari_mch_type == ATARI_MACH_MEDUSA) +#define MACH_IS_HADES (atari_mch_type == ATARI_MACH_HADES) +#define MACH_IS_AB40 (atari_mch_type == ATARI_MACH_AB40) + +/* values for atari_switches */ +#define ATARI_SWITCH_IKBD 0x01 +#define ATARI_SWITCH_MIDI 0x02 +#define ATARI_SWITCH_SND6 0x04 +#define ATARI_SWITCH_SND7 0x08 +#define ATARI_SWITCH_OVSC_SHIFT 16 +#define ATARI_SWITCH_OVSC_IKBD (ATARI_SWITCH_IKBD << ATARI_SWITCH_OVSC_SHIFT) +#define ATARI_SWITCH_OVSC_MIDI (ATARI_SWITCH_MIDI << ATARI_SWITCH_OVSC_SHIFT) +#define ATARI_SWITCH_OVSC_SND6 (ATARI_SWITCH_SND6 << ATARI_SWITCH_OVSC_SHIFT) +#define ATARI_SWITCH_OVSC_SND7 (ATARI_SWITCH_SND7 << ATARI_SWITCH_OVSC_SHIFT) +#define ATARI_SWITCH_OVSC_MASK 0xffff0000 + /* * Define several Hardware-Chips for indication so that for the ATARI we do * no longer decide whether it is a Falcon or other machine . It's just @@ -92,14 +115,6 @@ #define MFPDELAY() \ __asm__ __volatile__ ( "tstb %0" : : "m" (mfp.par_dt_reg) : "cc" ); -/* Memory used for screen ram and stdma buffers */ -void atari_stram_init (void); -void *atari_stram_alloc (long size, unsigned long *start_mem ); -void atari_stram_free (void *); - -extern int is_medusa; -extern int is_hades; - /* Do cache push/invalidate for DMA read/write. This function obeys the * snooping on some machines (Medusa) and processors: The Medusa itself can * snoop, but only the '040 can source data from its cache to DMA writes i.e., @@ -116,11 +131,11 @@ { if (writeflag) { - if (!is_medusa || CPU_IS_060) + if (!MACH_IS_MEDUSA || CPU_IS_060) cache_push( paddr, len ); } else { - if (!is_medusa) + if (!MACH_IS_MEDUSA) cache_clear( paddr, len ); } } diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h --- v2.1.86/linux/include/asm-m68k/bitops.h Wed Dec 3 06:18:17 1997 +++ linux/include/asm-m68k/bitops.h Thu Feb 12 16:30:13 1998 @@ -14,7 +14,23 @@ * They use the standard big-endian m680x0 bit ordering. */ -extern __inline__ int test_and_set_bit(int nr,void * vaddr) +#define test_and_set_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_test_and_set_bit(nr, vaddr) : \ + __generic_test_and_set_bit(nr, vaddr)) + +extern __inline__ int __constant_test_and_set_bit(int nr,void * vaddr) +{ + char retval; + + __asm__ __volatile__ ("bset %1,%2; sne %0" + : "=d" (retval) + : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3])); + + return retval; +} + +extern __inline__ int __generic_test_and_set_bit(int nr,void * vaddr) { char retval; @@ -24,13 +40,40 @@ return retval; } -extern __inline__ void set_bit(int nr, void * vaddr) +#define set_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_set_bit(nr, vaddr) : \ + __generic_set_bit(nr, vaddr)) + +extern __inline__ void __constant_set_bit(int nr, void * vaddr) +{ + __asm__ __volatile__ ("bset %0,%1" + : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3])); +} + +extern __inline__ void __generic_set_bit(int nr, void * vaddr) { __asm__ __volatile__ ("bfset %1@{%0:#1}" : : "d" (nr^31), "a" (vaddr)); } -extern __inline__ int test_and_clear_bit(int nr, void * vaddr) +#define test_and_clear_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_test_and_clear_bit(nr, vaddr) : \ + __generic_test_and_clear_bit(nr, vaddr)) + +extern __inline__ int __constant_test_and_clear_bit(int nr, void * vaddr) +{ + char retval; + + __asm__ __volatile__ ("bclr %1,%2; sne %0" + : "=d" (retval) + : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3])); + + return retval; +} + +extern __inline__ int __generic_test_and_clear_bit(int nr, void * vaddr) { char retval; @@ -40,13 +83,40 @@ return retval; } -extern __inline__ void clear_bit(int nr, void * vaddr) +#define clear_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_clear_bit(nr, vaddr) : \ + __generic_clear_bit(nr, vaddr)) + +extern __inline__ void __constant_clear_bit(int nr, void * vaddr) +{ + __asm__ __volatile__ ("bclr %0,%1" + : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3])); +} + +extern __inline__ void __generic_clear_bit(int nr, void * vaddr) { __asm__ __volatile__ ("bfclr %1@{%0:#1}" : : "d" (nr^31), "a" (vaddr)); } -extern __inline__ int test_and_change_bit(int nr, void * vaddr) +#define test_and_change_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_test_and_change_bit(nr, vaddr) : \ + __generic_test_and_change_bit(nr, vaddr)) + +extern __inline__ int __constant_test_and_change_bit(int nr, void * vaddr) +{ + char retval; + + __asm__ __volatile__ ("bchg %1,%2; sne %0" + : "=d" (retval) + : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3])); + + return retval; +} + +extern __inline__ int __generic_test_and_change_bit(int nr, void * vaddr) { char retval; @@ -56,7 +126,18 @@ return retval; } -extern __inline__ void change_bit(int nr, void * vaddr) +#define change_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_change_bit(nr, vaddr) : \ + __generic_change_bit(nr, vaddr)) + +extern __inline__ void __constant_change_bit(int nr, void * vaddr) +{ + __asm__ __volatile__ ("bchg %0,%1" + : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3])); +} + +extern __inline__ void __generic_change_bit(int nr, void * vaddr) { __asm__ __volatile__ ("bfchg %1@{%0:#1}" : : "d" (nr^31), "a" (vaddr)); @@ -256,8 +337,5 @@ res = ext2_find_first_zero_bit (p, size - 32 * (p - addr)); return (p - addr) * 32 + res; } - - -/* Byte swapping (swab16 and swab32) is now in asm/byteorder.h . */ #endif /* _M68K_BITOPS_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h --- v2.1.86/linux/include/asm-m68k/bootinfo.h Wed Apr 23 19:01:27 1997 +++ linux/include/asm-m68k/bootinfo.h Thu Feb 12 16:30:13 1998 @@ -93,7 +93,73 @@ */ #define BI_ATARI_MCH_COOKIE 0x8000 /* _MCH cookie from TOS (u_long) */ +#define BI_ATARI_MCH_TYPE 0x8001 /* special machine type (u_long) */ + /* (values are ATARI_MACH_* defines */ +/* mch_cookie values (upper word) */ +#define ATARI_MCH_ST 0 +#define ATARI_MCH_STE 1 +#define ATARI_MCH_TT 2 +#define ATARI_MCH_FALCON 3 + +/* mch_type values */ +#define ATARI_MACH_NORMAL 0 /* no special machine type */ +#define ATARI_MACH_MEDUSA 1 /* Medusa 040 */ +#define ATARI_MACH_HADES 2 /* Hades 040 or 060 */ +#define ATARI_MACH_AB40 3 /* Afterburner040 on Falcon */ + + /* + * Macintosh-specific tags + */ + +#define BI_MAC_MODEL 0x8000 /* Mac Gestalt ID (model type) */ +#define BI_MAC_VADDR 0x8001 /* Mac video base address */ +#define BI_MAC_VDEPTH 0x8002 /* Mac video depth */ +#define BI_MAC_VROW 0x8003 /* Mac video rowbytes */ +#define BI_MAC_VDIM 0x8004 /* Mac video dimensions */ +#define BI_MAC_VLOGICAL 0x8005 /* Mac video logical base */ +#define BI_MAC_SCCBASE 0x8006 /* Mac SCC base address */ +#define BI_MAC_BTIME 0x8007 /* Mac boot time */ +#define BI_MAC_GMTBIAS 0x8008 /* Mac GMT timezone offset */ +#define BI_MAC_MEMSIZE 0x8009 /* Mac RAM size (sanity check) */ +#define BI_MAC_CPUID 0x800a /* Mac CPU type (sanity check) */ + + /* + * Mac: compatibility with old booter data format (temporarily) + */ + +#ifndef __ASSEMBLY__ + +struct mac_booter_data +{ + unsigned long videoaddr; + unsigned long videorow; + unsigned long videodepth; + unsigned long dimensions; + unsigned long args; + unsigned long boottime; + unsigned long gmtbias; + unsigned long bootver; + unsigned long videological; + unsigned long sccbase; + unsigned long id; + unsigned long memsize; + unsigned long serialmf; + unsigned long serialhsk; + unsigned long serialgpi; + unsigned long printmf; + unsigned long printhsk; + unsigned long printgpi; + unsigned long cpuid; + unsigned long rombase; + unsigned long adbdelay; + unsigned long timedbra; +}; + +extern struct mac_booter_data + mac_bi_data; + +#endif /* * Stuff for bootinfo interface versioning @@ -129,7 +195,9 @@ #endif /* __ASSEMBLY__ */ #define AMIGA_BOOTI_VERSION MK_BI_VERSION( 2, 0 ) -#define ATARI_BOOTI_VERSION MK_BI_VERSION( 2, 0 ) +#define ATARI_BOOTI_VERSION MK_BI_VERSION( 2, 1 ) +#define MAC_BOOTI_VERSION MK_BI_VERSION( 2, 0 ) +#define MVME16x_BOOTI_VERSION MK_BI_VERSION( 2, 0 ) #ifdef BOOTINFO_COMPAT_1_0 @@ -140,6 +208,7 @@ #define COMPAT_AMIGA_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) #define COMPAT_ATARI_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) +#define COMPAT_MAC_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) #include @@ -162,6 +231,67 @@ unsigned long mch_cookie; }; +#ifndef __ASSEMBLY__ + +#define MACHW_DECLARE(name) unsigned name : 1 +#define MACHW_SET(name) (boot_info.bi_mac.hw_present.name = 1) +#define MACHW_PRESENT(name) (boot_info.bi_mac.hw_present.name) + +struct compat_bi_Macintosh +{ + unsigned long videoaddr; + unsigned long videorow; + unsigned long videodepth; + unsigned long dimensions; + unsigned long args; + unsigned long boottime; + unsigned long gmtbias; + unsigned long bootver; + unsigned long videological; + unsigned long sccbase; + unsigned long id; + unsigned long memsize; + unsigned long serialmf; + unsigned long serialhsk; + unsigned long serialgpi; + unsigned long printmf; + unsigned long printhsk; + unsigned long printgpi; + unsigned long cpuid; + unsigned long rombase; + unsigned long adbdelay; + unsigned long timedbra; + struct { + /* video hardware */ + /* sound hardware */ + /* disk storage interfaces */ + MACHW_DECLARE(MAC_SCSI); /* Directly mapped NCR5380 */ + MACHW_DECLARE(IDE); /* IDE Interface */ + /* other I/O hardware */ + MACHW_DECLARE(SCC); /* Serial Communications Contr. */ + /* DMA */ + MACHW_DECLARE(SCSI_DMA); /* DMA for the NCR5380 */ + /* real time clocks */ + MACHW_DECLARE(RTC_CLK); /* clock chip */ + /* supporting hardware */ + MACHW_DECLARE(VIA1); /* Versatile Interface Ad. 1 */ + MACHW_DECLARE(VIA2); /* Versatile Interface Ad. 2 */ + MACHW_DECLARE(RBV); /* Versatile Interface Ad. 2+ */ + /* NUBUS */ + MACHW_DECLARE(NUBUS); /* NUBUS */ + } hw_present; +}; +#else + +#define BI_videoaddr BI_un +#define BI_videorow BI_videoaddr+4 +#define BI_videodepth BI_videorow+4 +#define BI_dimensions BI_videodepth+4 +#define BI_args BI_dimensions+4 +#define BI_cpuid BI_args+56 + +#endif + struct compat_mem_info { unsigned long addr; unsigned long size; @@ -200,13 +330,15 @@ unsigned long ramdisk_addr; char command_line[COMPAT_CL_SIZE]; union { - struct compat_bi_Amiga bi_ami; - struct compat_bi_Atari bi_ata; + struct compat_bi_Amiga bi_ami; + struct compat_bi_Atari bi_ata; + struct compat_bi_Macintosh bi_mac; } bi_un; }; #define bi_amiga bi_un.bi_ami #define bi_atari bi_un.bi_ata +#define bi_mac bi_un.bi_mac #endif /* BOOTINFO_COMPAT_1_0 */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/bugs.h linux/include/asm-m68k/bugs.h --- v2.1.86/linux/include/asm-m68k/bugs.h Wed Dec 27 12:46:49 1995 +++ linux/include/asm-m68k/bugs.h Thu Feb 12 16:30:13 1998 @@ -11,6 +11,4 @@ * void check_bugs(void); */ -static void check_bugs(void) -{ -} +extern void check_bugs(void); /* in arch/m68k/kernel/setup.c */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h --- v2.1.86/linux/include/asm-m68k/entry.h Mon Jun 16 16:36:00 1997 +++ linux/include/asm-m68k/entry.h Thu Feb 12 16:30:13 1998 @@ -40,12 +40,11 @@ /* * these are offsets into the task-struct */ -LTASK_STATE = 0 -LTASK_COUNTER = 4 -LTASK_PRIORITY = 8 -LTASK_SIGNAL = 12 -LTASK_BLOCKED = 16 -LTASK_FLAGS = 20 +LTASK_STATE = 0 +LTASK_FLAGS = 4 +LTASK_SIGPENDING = 8 +LTASK_ADDRLIMIT = 12 +LTASK_EXECDOMAIN = 16 LTSS_KSP = 0 LTSS_USP = 4 @@ -55,7 +54,7 @@ LTSS_FPCTXT = 24 /* the following macro is used when enabling interrupts */ -#if defined(MACH_ATARI_ONLY) +#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES) /* block out HSYNC on the atari */ #define ALLOWINT 0xfbff #define MAX_NOINT_IPL 3 diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/font.h linux/include/asm-m68k/font.h --- v2.1.86/linux/include/asm-m68k/font.h Sun May 19 21:54:29 1996 +++ linux/include/asm-m68k/font.h Wed Dec 31 16:00:00 1969 @@ -1,35 +0,0 @@ -/* - * asm-m68k/font.h -- `Soft' font definitions - * - * Created 1995 by Geert Uytterhoeven - * - * 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 _ASM_M68K_FONT_H_ -#define _ASM_M68K_FONT_H_ - -#include - - - /* - * Find a font with a specific name - */ - -extern int findsoftfont(char *name, int *width, int *height, u_char *data[]); - - - /* - * Get the default font for a specific screen size - */ - -extern void getdefaultfont(int xres, int yres, char *name[], int *width, - int *height, u_char *data[]); - - -/* Max. length for the name of a predefined font */ -#define MAX_FONT_NAME 32 - -#endif /* _ASM_M68K_FONT_H_ */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h --- v2.1.86/linux/include/asm-m68k/hardirq.h Mon Jul 7 08:18:55 1997 +++ linux/include/asm-m68k/hardirq.h Thu Feb 12 16:30:13 1998 @@ -4,7 +4,6 @@ #include extern unsigned int local_irq_count[NR_CPUS]; -#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) #define hardirq_trylock(cpu) (++local_irq_count[cpu], (cpu) == 0) #define hardirq_endlock(cpu) (--local_irq_count[cpu]) diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h --- v2.1.86/linux/include/asm-m68k/ide.h Wed Apr 23 19:01:27 1997 +++ linux/include/asm-m68k/ide.h Thu Feb 12 16:30:13 1998 @@ -33,28 +33,18 @@ #include -#ifdef CONFIG_AMIGA -#include -#include -#include -#endif /* CONFIG_AMIGA */ - -#ifdef CONFIG_ATARI -#include /* intr_count */ -#include -#include -#include -#include -#endif /* CONFIG_ATARI */ - #include #include #include +#ifdef CONFIG_ATARI +#include +#endif + typedef unsigned char * ide_ioreg_t; #ifndef MAX_HWIFS -#define MAX_HWIFS 1 +#define MAX_HWIFS 4 /* same as the other archs */ #endif static __inline int ide_default_irq (ide_ioreg_t base) @@ -62,68 +52,12 @@ return 0; } -static __inline__ ide_ioreg_t ide_default_io_base (int index) -{ - if (index) - return NULL; -#ifdef CONFIG_AMIGA - if (MACH_IS_AMIGA) { - if (AMIGAHW_PRESENT(A4000_IDE)) { - printk("Gayle IDE interface (A%d style)\n", 4000); - return ((ide_ioreg_t)ZTWO_VADDR(HD_BASE_A4000)); - } - if (AMIGAHW_PRESENT(A1200_IDE)) { - printk("Gayle IDE interface (A%d style)\n", 1200); - return ((ide_ioreg_t)ZTWO_VADDR(HD_BASE_A1200)); - } - } -#endif /* CONFIG_AMIGA */ -#ifdef CONFIG_ATARI - if (MACH_IS_ATARI) { - if (ATARIHW_PRESENT(IDE)) { - printk("Falcon IDE interface\n"); - return ((ide_ioreg_t) ATA_HD_BASE); - } - } -#endif /* CONFIG_ATARI */ - return NULL; -} - +/* + * Can we do this in a generic manner?? + */ static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) { - *p++ = base; -#ifdef CONFIG_AMIGA - if (MACH_IS_AMIGA) { - *p++ = base + AMI_HD_ERROR; - *p++ = base + AMI_HD_NSECTOR; - *p++ = base + AMI_HD_SECTOR; - *p++ = base + AMI_HD_LCYL; - *p++ = base + AMI_HD_HCYL; - *p++ = base + AMI_HD_SELECT; - *p++ = base + AMI_HD_STATUS; - *p++ = base + AMI_HD_CMD; - if (AMIGAHW_PRESENT(A4000_IDE)) - *p++ = (ide_ioreg_t) ZTWO_VADDR(HD_A4000_IRQ); - else if (AMIGAHW_PRESENT(A1200_IDE)) - *p++ = (ide_ioreg_t) ZTWO_VADDR(HD_A1200_IRQ); - if (irq != NULL) - *irq = IRQ_AMIGA_PORTS; - } -#endif /* CONFIG_AMIGA */ -#ifdef CONFIG_ATARI - if (MACH_IS_ATARI) { - *p++ = base + ATA_HD_ERROR; - *p++ = base + ATA_HD_NSECTOR; - *p++ = base + ATA_HD_SECTOR; - *p++ = base + ATA_HD_LCYL; - *p++ = base + ATA_HD_HCYL; - *p++ = base + ATA_HD_CURRENT; - *p++ = base + ATA_HD_STATUS; - *p++ = base + ATA_HD_CMD; - if (irq != NULL) - *irq = IRQ_MFP_IDE; - } -#endif /* CONFIG_ATARI */ + printk("ide_init_hwif_ports: must not be called\n"); } typedef union { @@ -363,23 +297,6 @@ #endif /* CONFIG_ATARI */ -static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port) -{ -#ifdef CONFIG_AMIGA - if (MACH_IS_AMIGA) { - unsigned char ch; - ch = inb(irq_port); - if (!(ch & 0x80)) - return(0); - if (AMIGAHW_PRESENT(A1200_IDE)) { - (void) inb(status_port); - outb(0x7c | (ch & 0x03), irq_port); - } - } -#endif /* CONFIG_AMIGA */ - return(1); -} - #define T_CHAR (0x0000) /* char: don't touch */ #define T_SHORT (0x4000) /* short: 12 -> 21 */ #define T_INT (0x8000) /* int: 1234 -> 4321 */ @@ -488,6 +405,8 @@ } #endif /* CONFIG_ATARI */ } + +#define ide_ack_intr(hwif) (hwif)->ack_intr((hwif)) /* * On the Atari, we sometimes can't enable interrupts: diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/init.h linux/include/asm-m68k/init.h --- v2.1.86/linux/include/asm-m68k/init.h Tue May 13 22:41:17 1997 +++ linux/include/asm-m68k/init.h Thu Feb 12 16:30:13 1998 @@ -1,6 +1,10 @@ #ifndef _M68K_INIT_H #define _M68K_INIT_H +#include + +#ifndef CONFIG_KGDB + #define __init __attribute__ ((__section__ (".text.init"))) #define __initdata __attribute__ ((__section__ (".data.init"))) #define __initfunc(__arginit) \ @@ -11,4 +15,19 @@ #define __FINIT .previous #define __INITDATA .section ".data.init",#alloc,#write +#else + +/* gdb doesn't like it all if the code for one source file isn't together in + * the executable, so we must avoid the .init sections :-( */ + +#define __init +#define __initdata +#define __initfunc(__arginit) __arginit +/* For assembly routines */ +#define __INIT +#define __FINIT +#define __INITDATA + +#endif /* CONFIG_KGDB */ + #endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h --- v2.1.86/linux/include/asm-m68k/io.h Fri Nov 22 05:56:36 1996 +++ linux/include/asm-m68k/io.h Thu Feb 12 16:30:13 1998 @@ -3,15 +3,29 @@ #ifdef __KERNEL__ +#include + +#ifdef CONFIG_ATARI +#include + +#define SLOW_DOWN_IO do { if (MACH_IS_ATARI) MFPDELAY(); } while (0) +#endif + /* * 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 * memory location directly. */ -#define readb(addr) (*(volatile unsigned char *) (addr)) -#define readw(addr) (*(volatile unsigned short *) (addr)) -#define readl(addr) (*(volatile unsigned int *) (addr)) +/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates + * two accesses to memory, which may be undesireable for some devices. + */ +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) +#define readl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; }) #define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) #define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b)) @@ -44,10 +58,16 @@ } /* - * IO bus memory addresses are 1:1 with the physical address + * IO bus memory addresses are 1:1 with the physical address, + * except on the PCI bus of the Hades. */ +#ifdef CONFIG_HADES +#define virt_to_bus(a) (virt_to_phys(a) + (MACH_IS_HADES ? 0x80000000 : 0)) +#define bus_to_virt(a) (phys_to_virt((a) - (MACH_IS_HADES ? 0x80000000 : 0))) +#else #define virt_to_bus virt_to_phys #define bus_to_virt phys_to_virt +#endif #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ioctls.h linux/include/asm-m68k/ioctls.h --- v2.1.86/linux/include/asm-m68k/ioctls.h Thu Dec 4 13:09:01 1997 +++ linux/include/asm-m68k/ioctls.h Thu Feb 12 16:25:04 1998 @@ -47,6 +47,8 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/keyboard.h linux/include/asm-m68k/keyboard.h --- v2.1.86/linux/include/asm-m68k/keyboard.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/keyboard.h Thu Feb 12 16:30:13 1998 @@ -49,8 +49,16 @@ mach_kbd_leds(leds); } +#ifdef CONFIG_MAGIC_SYSRQ +#define kbd_is_sysrq(keycode) ((keycode) == mach_sysrq_key && \ + (up_flag || \ + (shift_state & mach_sysrq_shift_mask) == \ + mach_sysrq_shift_state)) +#define kbd_sysrq_xlate mach_sysrq_xlate +#endif + #define kbd_init_hw mach_keyb_init #endif /* __KERNEL__ */ -#endif /* __ASMm68k_KEYBOARD_H */ +#endif /* __M68K_KEYBOARD_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/mac_asc.h linux/include/asm-m68k/mac_asc.h --- v2.1.86/linux/include/asm-m68k/mac_asc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/mac_asc.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,27 @@ +/* + * Apple Sound Chip + */ + +#ifndef __ASM_MAC_ASC_H +#define __ASM_MAC_ASC_H + +/* + * ASC offsets and controls + */ + +#define ASC_BUF_BASE 0x00 /* RAM buffer offset */ +#define ASC_BUF_SIZE 0x800 + +#define ASC_CONTROL 0x800 +#define ASC_CONTROL_OFF 0x00 +#define ASC_FREQ(chan,byte) ((0x810)+((chan)<<3)+(byte)) +#define ASC_ENABLE 0x801 +#define ASC_ENABLE_SAMPLE 0x02 +#define ASC_MODE 0x802 +#define ASC_MODE_SAMPLE 0x02 + +#define ASC_VOLUME 0x806 +#define ASC_CHAN 0x807 /* ??? */ + + +#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/mac_mouse.h linux/include/asm-m68k/mac_mouse.h --- v2.1.86/linux/include/asm-m68k/mac_mouse.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/mac_mouse.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,23 @@ +#ifndef _ASM_MAC_MOUSE_H +#define _ASM_MAC_MOUSE_H + +/* + * linux/include/asm-m68k/mac_mouse.h + * header file for Macintosh ADB mouse driver + * 27-10-97 Michael Schmitz + * copied from: + * header file for Atari Mouse driver + * by Robert de Vries (robert@and.nl) on 19Jul93 + */ + +struct mouse_status { + char buttons; + short dx; + short dy; + int ready; + int active; + struct wait_queue *wait; + struct fasync_struct *fasyncptr; +}; + +#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h --- v2.1.86/linux/include/asm-m68k/machdep.h Wed Apr 23 19:01:27 1997 +++ linux/include/asm-m68k/machdep.h Thu Feb 12 16:30:13 1998 @@ -30,13 +30,15 @@ extern int (*mach_hwclk)(int, struct hwclk_time*); extern int (*mach_set_clock_mmss)(unsigned long); extern void (*mach_reset)( void ); -extern int (*mach_floppy_init) (void); extern unsigned long (*mach_hd_init) (unsigned long, unsigned long); extern void (*mach_hd_setup)(char *, int *); -extern struct fb_info *(*mach_fb_init)(long *); extern long mach_max_dma_address; -extern void (*mach_video_setup)(char *, int *); extern void (*mach_floppy_setup)(char *, int *); extern void (*mach_floppy_eject)(void); +extern void (*mach_heartbeat) (int); +extern int mach_sysrq_key; +extern int mach_sysrq_shift_state; +extern int mach_sysrq_shift_mask; +extern char *mach_sysrq_xlate; #endif /* _M68K_MACHDEP_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/machw.h linux/include/asm-m68k/machw.h --- v2.1.86/linux/include/asm-m68k/machw.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/machw.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,108 @@ +/* +** linux/machw.h -- This header defines some macros and pointers for +** the various Macintosh custom hardware registers. +** +** Copyright 1997 by Michael Schmitz +** +** 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 _ASM_MACHW_H_ +#define _ASM_MACHW_H_ + +#include + +/* Mac SCSI Controller 5380 */ + +#define MAC_5380_BAS (0x50F10000) /* This is definitely wrong!! */ +struct MAC_5380 { + u_char scsi_data; + u_char char_dummy1; + u_char scsi_icr; + u_char char_dummy2; + u_char scsi_mode; + u_char char_dummy3; + u_char scsi_tcr; + u_char char_dummy4; + u_char scsi_idstat; + u_char char_dummy5; + u_char scsi_dmastat; + u_char char_dummy6; + u_char scsi_targrcv; + u_char char_dummy7; + u_char scsi_inircv; +}; +#define mac_scsi ((*(volatile struct MAC_5380 *)MAC_5380_BAS)) + +/* +** SCC Z8530 +*/ + +#define MAC_SCC_BAS (0x50F04000) +struct MAC_SCC + { + u_char cha_a_ctrl; + u_char char_dummy1; + u_char cha_a_data; + u_char char_dummy2; + u_char cha_b_ctrl; + u_char char_dummy3; + 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) + +# define via2_regp ((volatile unsigned char *)VIA2_BAS) +# define via2_ci_regp ((volatile unsigned char *)VIA2_BAS_IIci) +# define rbv_regp ((volatile unsigned char *)VIA2_BAS_IIci) + +#endif /* linux/machw.h */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/macintosh.h linux/include/asm-m68k/macintosh.h --- v2.1.86/linux/include/asm-m68k/macintosh.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/macintosh.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,139 @@ +#ifndef __ASM_MACINTOSH_H +#define __ASM_MACINTOSH_H + +/* + * Apple Macintoshisms + */ + +extern void mac_reset(void); +extern void mac_init_IRQ(void); +extern int mac_request_irq (unsigned int, void (*)(int, void *, + struct pt_regs *), + unsigned long, const char *, void *); +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_get_irq_list(char *); +#if 0 +extern void mac_default_handler(int irq); +#endif +extern void mac_identify(void); +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 + */ + +extern void via1_set_head(int); + +extern void parse_booter(char *ptr); +extern void print_booter(char *ptr); + +/* + * Macintosh Table + */ + +struct mac_model *macintosh_config; + + +struct mac_model +{ + short ident; + char *name; + char adb_type; + char via_type; + char scsi_type; + char ide_type; + char scc_type; + char ether_type; + char nubus_type; +}; + +#define MAC_ADB_NONE 0 +#define MAC_ADB_II 1 +#define MAC_ADB_IISI 2 +#define MAC_ADB_CUDA 3 + +#define MAC_VIA_II 1 +#define MAC_VIA_IIci 2 +#define MAC_VIA_QUADRA 3 + +#define MAC_SCSI_NONE 0 +#define MAC_SCSI_OLD 1 +#define MAC_SCSI_QUADRA 2 +#define MAC_SCSI_QUADRA2 3 +#define MAC_SCSI_QUADRA3 4 + +#define MAC_IDE_NONE 0 +#define MAC_IDE_QUADRA 1 +#define MAC_IDE_PB 2 + +#define MAC_SCC_II 1 +#define MAC_SCC_QUADRA 2 +#define MAC_SCC_QUADRA2 3 + +#define MAC_ETHER_NONE 0 +#define MAC_ETHER_SONIC 1 + +#define MAC_NO_NUBUS 0 +#define MAC_NUBUS 1 + +/* + * Gestalt numbers + */ + +#define MAC_MODEL_II 6 +#define MAC_MODEL_IIX 7 +#define MAC_MODEL_IICX 8 +#define MAC_MODEL_SE30 9 +#define MAC_MODEL_IICI 11 +#define MAC_MODEL_IIFX 13 /* And well numbered it is too */ +#define MAC_MODEL_IISI 18 +#define MAC_MODEL_Q900 20 +#define MAC_MODEL_PB170 25 +#define MAC_MODEL_Q700 22 +#define MAC_MODEL_CLII 23 +#define MAC_MODEL_PB140 25 +#define MAC_MODEL_Q950 26 +#define MAC_MODEL_LCIII 27 /* aka: P450 */ +#define MAC_MODEL_PB210 29 +#define MAC_MODEL_C650 30 +#define MAC_MODEL_PB230 32 +#define MAC_MODEL_PB180 33 +#define MAC_MODEL_PB160 34 +#define MAC_MODEL_Q800 35 +#define MAC_MODEL_Q650 36 +#define MAC_MODEL_LCII 37 /* aka: P400/405/410/430 */ +#define MAC_MODEL_PB250 38 +#define MAC_MODEL_IIVI 44 +#define MAC_MODEL_IIVX 48 +#define MAC_MODEL_CCL 49 +#define MAC_MODEL_PB165C 50 +#define MAC_MODEL_C610 52 +#define MAC_MODEL_Q610 53 +#define MAC_MODEL_PB145 54 +#define MAC_MODEL_P520 56 /* aka: LC520 */ +#define MAC_MODEL_C660 60 +#define MAC_MODEL_P460 62 /* aka: LCIII+, P466/7 */ +#define MAC_MODEL_PB180C 71 +#define MAC_MODEL_PB520 72 +#define MAC_MODEL_PB270C 77 +#define MAC_MODEL_Q840 78 +#define MAC_MODEL_P550 80 +#define MAC_MODEL_PB165 84 +#define MAC_MODEL_PB190 85 +#define MAC_MODEL_TV 88 +#define MAC_MODEL_P475 89 /* aka: LC475, P476 */ +#define MAC_MODEL_P575 92 /* aka: LC575/580, P577/578/508 */ +#define MAC_MODEL_Q605 94 +#define MAC_MODEL_Q630 98 /* aka: LC630, P630/631/636/640 */ +#define MAC_MODEL_PB280 102 +#define MAC_MODEL_PB280C 103 +#define MAC_MODEL_PB150 115 + +extern struct mac_model *macintosh_config; + +#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/macints.h linux/include/asm-m68k/macints.h --- v2.1.86/linux/include/asm-m68k/macints.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/macints.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,160 @@ +/* +** macints.h -- Macintosh Linux interrupt handling structs and prototypes +** +** Copyright 1997 by Michael Schmitz +** +** 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 _ASM_MACINTS_H_ +#define _ASM_MACINTS_H_ + +#include + +/* +** Macintosh Interrupt sources. +** +** Note: these are all routed via the generic VIA interrupt routine! +** +*/ + +#define SRC_VIA1 0 +#define SRC_VIA2 1 + +#define VIA1_SOURCE_BASE 8 +#define VIA2_SOURCE_BASE 16 +#define RBF_SOURCE_BASE 24 +#define MAC_SCC_SOURCE_BASE 32 +#define NUBUS_SOURCE_BASE 40 +#define NUBUS_MAX_SOURCES 8 + +/* FIXME: sources not contigous ... */ +#define NUM_MAC_SOURCES (NUBUS_SOURCE_BASE+NUBUS_MAX_SOURCES-VIA1_SOURCE_BASE) + +#define IRQ_SRC_MASK (VIA1_SOURCE_BASE|VIA2_SOURCE_BASE|MAC_SCC_SOURCE_BASE) +#define IRQ_IDX_MASK 7 + +/* + * quick hack to adapt old MACHSPEC-aware source + */ +#define IRQ_IDX(irq) (irq) + +#if 0 +/* convert vector number to int source number */ +#define IRQ_VECTOR_TO_SOURCE(v) (v) + +/* convert irq_handler index to vector number */ +#define IRQ_SOURCE_TO_VECTOR(i) (i) +#endif + +/* interrupt service types */ +#define IRQ_TYPE_SLOW 0 +#define IRQ_TYPE_FAST 1 +#define IRQ_TYPE_PRIO 2 + +#define IRQ_SPURIOUS (0) + +/* auto-vector interrupts */ +#define IRQ_AUTO_1 (1) +#define IRQ_AUTO_2 (2) +#define IRQ_AUTO_3 (3) +#define IRQ_AUTO_4 (4) +#define IRQ_AUTO_5 (5) +#define IRQ_AUTO_6 (6) +#define IRQ_AUTO_7 (7) + +/* VIA1 interrupts */ +#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_MAC_ADB IRQ_VIA1_2 +#define IRQ_MAC_ADB_SR IRQ_VIA1_2 +#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_MAC_ADB_CL IRQ_VIA1_4 +#define IRQ_VIA1_5 (13) +#define IRQ_MAC_TIMER_2 IRQ_VIA1_5 +#define IRQ_VIA1_6 (14) +#define IRQ_MAC_TIMER_1 IRQ_VIA1_6 +#define IRQ_VIA1_7 (15) + +/* VIA2 interrupts */ +#define IRQ_VIA2_0 (16) +#define IRQ_MAC_SCSIDRQ IRQ_VIA2_0 +#define IRQ_VIA2_1 (17) +#define IRQ_MAC_NUBUS IRQ_VIA2_1 +#define IRQ_VIA2_2 (18) +#define IRQ_VIA2_3 (19) +#define IRQ_MAC_SCSI IRQ_VIA2_3 +#define IRQ_VIA2_4 (20) +#define IRQ_VIA2_5 (21) +#define IRQ_VIA2_6 (22) +#define IRQ_VIA2_7 (23) + +/* 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) + +#define IRQ_SCC (32) +#define IRQ_SCCB (32) +#define IRQ_SCCA (33) +#if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */ +/* SCC interrupts */ +#define IRQ_SCCB_TX (32) +#define IRQ_SCCB_STAT (33) +#define IRQ_SCCB_RX (34) +#define IRQ_SCCB_SPCOND (35) +#define IRQ_SCCA_TX (36) +#define IRQ_SCCA_STAT (37) +#define IRQ_SCCA_RX (38) +#define IRQ_SCCA_SPCOND (39) +#endif + +#define IRQ_NUBUS_1 (40) + +#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 (*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); + +#endif /* asm/macints.h */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/mvme16xhw.h linux/include/asm-m68k/mvme16xhw.h --- v2.1.86/linux/include/asm-m68k/mvme16xhw.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/mvme16xhw.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,118 @@ +#ifndef _M68K_MVME16xHW_H_ +#define _M68K_MVME16xHW_H_ + +#include + +/* Board ID data structure - pointer to this retrieved from Bug by head.S */ + +/* Note, bytes 12 and 13 are board no in BCD (0162,0166,0167,0177,etc) */ + +extern long mvme_bdid_ptr; + +typedef struct { + char bdid[4]; + u_char rev, mth, day, yr; + u_short size, reserved; + u_short brdno; + char brdsuffix[2]; + u_long options; + u_short clun, dlun, ctype, dnum; + u_long option2; +} t_bdid, *p_bdid; + + +typedef struct { + u_char ack_icr, + flt_icr, + sel_icr, + pe_icr, + bsy_icr, + spare1, + isr, + cr, + spare2, + spare3, + spare4, + data; +} lpr_ctrl; + +#define LPR_REGS ((volatile lpr_ctrl *)0xfff42030) + +#define I596_BASE 0xfff46000 + +#define SCC_A_ADDR 0xfff45005 +#define SCC_B_ADDR 0xfff45001 + +#define IRQ_MVME162_TYPE_PRIO 0 + +#define IRQ_MVME167_PRN 0x54 +#define IRQ_MVME16x_I596 0x57 +#define IRQ_MVME16x_SCSI 0x55 +#define IRQ_MVME16x_FLY 0x7f +#define IRQ_MVME167_SER_ERR 0x5c +#define IRQ_MVME167_SER_MODEM 0x5d +#define IRQ_MVME167_SER_TX 0x5e +#define IRQ_MVME167_SER_RX 0x5f +#define IRQ_MVME16x_TIMER 0x59 + +/* SCC interrupts, for MVME162 */ +#define IRQ_MVME162_SCC_BASE 0x40 +#define IRQ_MVME162_SCCB_TX 0x40 +#define IRQ_MVME162_SCCB_STAT 0x42 +#define IRQ_MVME162_SCCB_RX 0x44 +#define IRQ_MVME162_SCCB_SPCOND 0x46 +#define IRQ_MVME162_SCCA_TX 0x48 +#define IRQ_MVME162_SCCA_STAT 0x4a +#define IRQ_MVME162_SCCA_RX 0x4c +#define IRQ_MVME162_SCCA_SPCOND 0x4e + +/* MVME162 version register */ + +#define MVME162_VERSION_REG 0xfff4202e + +extern unsigned short mvme16x_config; + +/* Lower 8 bits must match the revision register in the MC2 chip */ + +#define MVME16x_CONFIG_SPEED_32 0x0001 +#define MVME16x_CONFIG_NO_VMECHIP2 0x0002 +#define MVME16x_CONFIG_NO_SCSICHIP 0x0004 +#define MVME16x_CONFIG_NO_ETHERNET 0x0008 +#define MVME16x_CONFIG_GOT_FPU 0x0010 + +#define MVME16x_CONFIG_GOT_LP 0x0100 +#define MVME16x_CONFIG_GOT_CD2401 0x0200 +#define MVME16x_CONFIG_GOT_SCCA 0x0400 +#define MVME16x_CONFIG_GOT_SCCB 0x0800 + +/* Specials for the ethernet driver */ + +#define CA() (((struct i596_reg *)dev->base_addr)->ca = 1) + +#define MPU_PORT(c,x) \ + ((struct i596_reg *)(dev->base_addr))->porthi = ((c) | (u32)(x)) & 0xffff; \ + ((struct i596_reg *)(dev->base_addr))->portlo = ((c) | (u32)(x)) >> 16 + +#define SCP_SYSBUS 0x00000054 + +#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) + +/* + * The MPU_PORT command allows direct access to the 82596. With PORT access + * the following commands are available (p5-18). The 32-bit port command + * must be word-swapped with the most significant word written first. + */ +#define PORT_RESET 0x00 /* reset 82596 */ +#define PORT_SELFTEST 0x01 /* selftest */ +#define PORT_ALTSCP 0x02 /* alternate SCB address */ +#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */ + +#define ISCP_BUSY 0x00010000 + +#endif /* _M68K_MVME16xHW_H_ */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h --- v2.1.86/linux/include/asm-m68k/pgtable.h Sat Aug 16 09:51:09 1997 +++ linux/include/asm-m68k/pgtable.h Thu Feb 12 16:30:13 1998 @@ -26,7 +26,7 @@ asm __volatile__ ("nop\n\t" \ ".chip 68040\n\t" \ "cinva %%ic\n\t" \ - ".chip 68k"); \ + ".chip 68k" : ); \ else { \ unsigned long _tmp; \ asm __volatile__ ("movec %%cacr,%0\n\t" \ @@ -136,9 +136,12 @@ } /* Push n pages at kernel virtual address and clear the icache */ -extern inline void flush_pages_to_ram (unsigned long address, int n) +extern inline void flush_icache_range (unsigned long address, + unsigned long endaddr) { if (CPU_IS_040_OR_060) { + short n = (endaddr - address + PAGE_SIZE - 1) / PAGE_SIZE; + while (n--) { __asm__ __volatile__ ("nop\n\t" ".chip 68040\n\t" @@ -159,7 +162,6 @@ } } -#define flush_icache_range(start, end) do { } while (0) /* * flush all user-space atc entries. @@ -223,7 +225,7 @@ extern inline void flush_tlb_kernel_page(unsigned long addr) { if (CPU_IS_040_OR_060) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); __asm__ __volatile__(".chip 68040\n\t" "pflush (%0)\n\t" @@ -298,6 +300,8 @@ #define _PAGE_RONLY 0x004 #define _PAGE_ACCESSED 0x008 #define _PAGE_DIRTY 0x010 +#define _PAGE_SUPER 0x080 /* 68040 supervisor only */ +#define _PAGE_FAKE_SUPER 0x200 /* fake supervisor only on 680[23]0 */ #define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */ #define _PAGE_COW 0x800 /* implemented in software */ #define _PAGE_NOCACHE030 0x040 /* 68030 no-cache mode */ @@ -440,7 +444,7 @@ { return PTOV(pgd_val(pgd) & _TABLE_MASK); } extern inline int pte_none(pte_t pte) { return !pte_val(pte); } -extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } +extern inline int pte_present(pte_t pte) { return pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER); } extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } extern inline int pmd_none2(pmd_t *pmd) { return !pmd_val(*pmd); } @@ -728,12 +732,15 @@ int mm_end_of_chunk (unsigned long addr, int len); /* - * Map some physical address range into the kernel address space. The - * code is copied and adapted from map_chunk(). + * Map some physical address range into the kernel address space. */ extern unsigned long kernel_map(unsigned long paddr, unsigned long size, int nocacheflag, unsigned long *memavailp ); /* + * Unmap a region alloced by kernel_map(). + */ +extern void kernel_unmap( unsigned long addr ); +/* * Change the cache mode of some kernel address range. */ extern void kernel_set_cachemode( unsigned long address, unsigned long size, @@ -758,6 +765,8 @@ * I don't know what is going on here, but since these were changed, * swapping hasn't been working on the 68040. */ +/* With the new handling of PAGE_NONE the old definitions definitely + don't work any more. */ #define SWP_TYPE(entry) (((entry) >> 2) & 0x7f) #if 0 diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h --- v2.1.86/linux/include/asm-m68k/processor.h Fri Jan 16 20:37:01 1998 +++ linux/include/asm-m68k/processor.h Thu Feb 12 16:30:13 1998 @@ -48,7 +48,7 @@ #define INIT_TSS { \ sizeof(init_stack) + (unsigned long) init_stack, 0, \ - PS_S, KERNEL_DS, \ + PS_S, __KERNEL_DS, \ {0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \ } @@ -58,13 +58,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp) { - unsigned long nilstate = 0; - - /* clear floating point state */ - __asm__ __volatile__ (".chip 68k/68881\n\t" - "frestore %0@\n\t" - ".chip 68k" : : "a" (&nilstate)); - /* reads from user space */ set_fs(USER_DS); @@ -74,7 +67,16 @@ } /* Free all resources held by a thread. */ -extern void release_thread(struct task_struct *); +static inline void release_thread(struct task_struct *dead_task) +{ +} + +/* + * Free current thread data structures etc.. + */ +static inline void exit_thread(void) +{ +} /* * Return saved PC of a blocked thread. diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ptrace.h linux/include/asm-m68k/ptrace.h --- v2.1.86/linux/include/asm-m68k/ptrace.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/ptrace.h Thu Feb 12 16:30:13 1998 @@ -58,6 +58,12 @@ unsigned long retpc; }; +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 + #ifdef __KERNEL__ #ifndef PS_S diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/segment.h linux/include/asm-m68k/segment.h --- v2.1.86/linux/include/asm-m68k/segment.h Fri Nov 22 05:56:36 1996 +++ linux/include/asm-m68k/segment.h Thu Feb 12 16:30:13 1998 @@ -4,43 +4,53 @@ /* define constants */ /* Address spaces (FC0-FC2) */ #define USER_DATA (1) -#ifndef USER_DS -#define USER_DS (USER_DATA) +#ifndef __USER_DS +#define __USER_DS (USER_DATA) #endif #define USER_PROGRAM (2) #define SUPER_DATA (5) -#ifndef KERNEL_DS -#define KERNEL_DS (SUPER_DATA) +#ifndef __KERNEL_DS +#define __KERNEL_DS (SUPER_DATA) #endif #define SUPER_PROGRAM (6) #define CPU_SPACE (7) #ifndef __ASSEMBLY__ +typedef struct { + unsigned long seg; +} mm_segment_t; + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define USER_DS MAKE_MM_SEG(__USER_DS) +#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) + /* * Get/set the SFC/DFC registers for MOVES instructions */ -static inline unsigned long get_fs(void) +static inline mm_segment_t get_fs(void) { - unsigned long _v; - __asm__ ("movec %/dfc,%0":"=r" (_v):); + mm_segment_t _v; + __asm__ ("movec %/dfc,%0":"=r" (_v.seg):); return _v; } -static inline unsigned long get_ds(void) +static inline mm_segment_t get_ds(void) { /* return the supervisor data space code */ return KERNEL_DS; } -static inline void set_fs(unsigned long val) +static inline void set_fs(mm_segment_t val) { __asm__ __volatile__ ("movec %0,%/sfc\n\t" "movec %0,%/dfc\n\t" - : /* no outputs */ : "r" (val) : "memory"); + : /* no outputs */ : "r" (val.seg) : "memory"); } + +#define segment_eq(a,b) ((a).seg == (b).seg) #endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h --- v2.1.86/linux/include/asm-m68k/serial.h Thu Jul 31 13:09:18 1997 +++ linux/include/asm-m68k/serial.h Thu Feb 12 16:30:13 1998 @@ -32,6 +32,8 @@ #define SER_IOEXT 106 /* Amiga GVP IO-Extender (16c552) */ #define SER_MFC_III 107 /* Amiga BSC Multiface Card III (MC68681) */ #define SER_WHIPPET 108 /* Amiga Hisoft Whippet PCMCIA (16c550B) */ +#define SER_SCC_MVME 109 /* MVME162/MVME172 ports */ +#define SER_SCC_MAC 110 /* Macintosh SCC channel */ struct serial_struct { int type; @@ -99,33 +101,33 @@ * */ -struct async_struct; +struct m68k_async_struct; typedef struct { - void (*init)( struct async_struct *info ); - void (*deinit)( struct async_struct *info, int leave_dtr ); - void (*enab_tx_int)( struct async_struct *info, int enab_flag ); - int (*check_custom_divisor)( struct async_struct *info, int baud_base, + void (*init)( struct m68k_async_struct *info ); + void (*deinit)( struct m68k_async_struct *info, int leave_dtr ); + void (*enab_tx_int)( struct m68k_async_struct *info, int enab_flag ); + int (*check_custom_divisor)( struct m68k_async_struct *info, int baud_base, int divisor ); - void (*change_speed)( struct async_struct *info ); - void (*throttle)( struct async_struct *info, int status ); - void (*set_break)( struct async_struct *info, int break_flag ); - void (*get_serial_info)( struct async_struct *info, + void (*change_speed)( struct m68k_async_struct *info ); + void (*throttle)( struct m68k_async_struct *info, int status ); + void (*set_break)( struct m68k_async_struct *info, int break_flag ); + void (*get_serial_info)( struct m68k_async_struct *info, struct serial_struct *retinfo ); - unsigned int (*get_modem_info)( struct async_struct *info ); - int (*set_modem_info)( struct async_struct *info, int new_dtr, + unsigned int (*get_modem_info)( struct m68k_async_struct *info ); + int (*set_modem_info)( struct m68k_async_struct *info, int new_dtr, int new_rts ); int (*ioctl)( struct tty_struct *tty, struct file *file, - struct async_struct *info, unsigned int cmd, + struct m68k_async_struct *info, unsigned int cmd, unsigned long arg ); - void (*stop_receive)( struct async_struct *info ); - int (*trans_empty)( struct async_struct *info ); - int (*check_open)( struct async_struct *info, struct tty_struct *tty, + void (*stop_receive)( struct m68k_async_struct *info ); + int (*trans_empty)( struct m68k_async_struct *info ); + int (*check_open)( struct m68k_async_struct *info, struct tty_struct *tty, struct file *file ); } SERIALSWITCH; /* - * Definitions for async_struct (and serial_struct) flags field + * Definitions for m68k_async_struct (and serial_struct) flags field */ #define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes on the callout port */ @@ -191,16 +193,18 @@ #include #include -/* - * Counters of the input lines (CTS, DSR, RI, CD) interrupts - */ -struct async_icount { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; +#include /* for Mac SCC extensions */ + +#ifdef CONFIG_MAC +#define NUM_ZSREGS 16 +struct mac_zschannel { + volatile unsigned char *control; + volatile unsigned char *data; }; +struct m68k_async_private; +#endif -struct async_struct { +struct m68k_async_struct { int magic; int baud_base; int port; @@ -233,15 +237,14 @@ int xmit_tail; int xmit_cnt; struct tq_struct tqueue; - struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; struct wait_queue *open_wait; struct wait_queue *close_wait; struct wait_queue *delta_msr_wait; struct async_icount icount; /* kernel counters for the 4 input interrupts */ - struct async_struct *next_port; /* For the linked list */ - struct async_struct *prev_port; + struct m68k_async_struct *next_port; /* For the linked list */ + struct m68k_async_struct *prev_port; void *board_base; /* board-base address for use with boards carrying several UART's, like some Amiga boards. */ @@ -254,8 +257,41 @@ interrupt, instead of checking IRQ-registers on all UART's */ SERIALSWITCH *sw; /* functions to manage this port */ +#ifdef CONFIG_MAC + struct m68k_async_private *private; +#endif }; +#ifdef CONFIG_MAC +struct m68k_async_private { + struct m68k_async_info *zs_next; /* For IRQ servicing chain */ + struct mac_zschannel *zs_channel; /* Channel registers */ + struct mac_zschannel *zs_chan_a; /* A side registers */ + unsigned char read_reg_zero; + + char soft_carrier; /* Use soft carrier on this */ + char break_abort; /* console, process brk/abrt */ + char kgdb_channel; /* Kgdb running on this channel */ + char is_cons; /* Is this our console. */ + unsigned char tx_active; /* character being xmitted */ + unsigned char tx_stopped; /* output is suspended */ + + /* We need to know the current clock divisor + * to read the bps rate the chip has currently + * loaded. + */ + unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ + int zs_baud; + + /* Current write register values */ + unsigned char curregs[NUM_ZSREGS]; + + /* Values we need to set next opportunity */ + unsigned char pendregs[NUM_ZSREGS]; + + char change_needed; +}; +#endif #define SERIAL_MAGIC 0x5301 /* @@ -275,7 +311,7 @@ /* Export to allow PCMCIA to use this - Dave Hinds */ extern int register_serial(struct serial_struct *req); extern void unregister_serial(int line); -extern struct async_struct rs_table[]; +extern struct m68k_async_struct rs_table[]; extern task_queue tq_serial; @@ -283,14 +319,14 @@ * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */ -static __inline__ void rs_sched_event(struct async_struct *info, int event) +static __inline__ void rs_sched_event(struct m68k_async_struct *info, int event) { info->event |= 1 << event; queue_task(&info->tqueue, &tq_serial); mark_bh(SERIAL_BH); } -static __inline__ void rs_receive_char( struct async_struct *info, +static __inline__ void rs_receive_char( struct m68k_async_struct *info, int ch, int err ) { struct tty_struct *tty = info->tty; @@ -305,10 +341,10 @@ *tty->flip.flag_buf_ptr++ = err; *tty->flip.char_buf_ptr++ = ch; info->icount.rx++; - queue_task(&tty->flip.tqueue, &tq_timer); + tty_flip_buffer_push(tty); } -static __inline__ int rs_get_tx_char( struct async_struct *info ) +static __inline__ int rs_get_tx_char( struct m68k_async_struct *info ) { unsigned char ch; @@ -330,14 +366,14 @@ return( ch ); } -static __inline__ int rs_no_more_tx( struct async_struct *info ) +static __inline__ int rs_no_more_tx( struct m68k_async_struct *info ) { return( info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped ); } -static __inline__ void rs_dcd_changed( struct async_struct *info, int dcd ) +static __inline__ void rs_dcd_changed( struct m68k_async_struct *info, int dcd ) { /* update input line counter */ @@ -356,7 +392,8 @@ #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - queue_task(&info->tqueue_hangup, &tq_scheduler); + if (info->tty) + tty_hangup(info->tty); } } } @@ -365,13 +402,13 @@ void rs_stop( struct tty_struct *tty ); void rs_start( struct tty_struct *tty ); -static __inline__ void rs_check_cts( struct async_struct *info, int cts ) +static __inline__ void rs_check_cts( struct m68k_async_struct *info, int cts ) { /* update input line counter */ info->icount.cts++; wake_up_interruptible(&info->delta_msr_wait); - if ((info->flags & ASYNC_CTS_FLOW) && info->tty) + if ((info->flags & ASYNC_CTS_FLOW) && info->tty) { if (info->tty->hw_stopped) { if (cts) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) @@ -388,7 +425,7 @@ rs_stop( info->tty ); } } - + } } diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h --- v2.1.86/linux/include/asm-m68k/setup.h Wed Apr 23 19:01:28 1997 +++ linux/include/asm-m68k/setup.h Thu Feb 12 16:30:13 1998 @@ -30,12 +30,14 @@ * Linux/m68k Architectures */ -#define MACH_AMIGA 1 -#define MACH_ATARI 2 -#define MACH_MAC 3 -#define MACH_APOLLO 4 -#define MACH_SUN3 5 -/* MVME 166/167/162/147?? */ +#define MACH_AMIGA 1 +#define MACH_ATARI 2 +#define MACH_MAC 3 +#define MACH_APOLLO 4 +#define MACH_SUN3 5 +#define MACH_MVME147 6 +#define MACH_MVME16x 7 +#define MACH_BVME6000 8 #ifdef __KERNEL__ @@ -45,7 +47,8 @@ #if !defined(CONFIG_AMIGA) # define MACH_IS_AMIGA (0) -#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) +#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \ + || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) # define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA) #else # define MACH_AMIGA_ONLY @@ -55,7 +58,8 @@ #if !defined(CONFIG_ATARI) # define MACH_IS_ATARI (0) -#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) +#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \ + || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) # define MACH_IS_ATARI (m68k_machtype == MACH_ATARI) #else # define MACH_ATARI_ONLY @@ -63,18 +67,56 @@ # define MACH_TYPE (MACH_ATARI) #endif -#if defined(CONFIG_MAC) -# error Currently no Mac support! +#if !defined(CONFIG_MAC) +# define MACH_IS_MAC (0) +#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) +# define MACH_IS_MAC (m68k_machtype == MACH_MAC) +#else +# define CONFIG_MAC_ONLY +# define MACH_IS_MAC (1) +# define MACH_TYPE (MACH_MAC) #endif #if defined(CONFIG_SUN3) # error Currently no Sun-3 support! +#else +#define MACH_IS_SUN3 (0) +#endif + +#if !defined (CONFIG_APOLLO) +# define MACH_IS_APOLLO (0) +#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ + || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) +# define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO) +#else +# define CONFIG_APOLLO_ONLY +# define MACH_IS_APOLLO (1) +# define MACH_TYPE (MACH_APOLLO) #endif -#if defined(CONFIG_APOLLO) -# error Currently no Apollo support! +#if !defined (CONFIG_MVME16x) +# define MACH_IS_MVME16x (0) +#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ + || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) +# define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x) +#else +# define CONFIG_MVME16x_ONLY +# define MACH_IS_MVME16x (1) +# define MACH_TYPE (MACH_MVME16x) #endif +#if !defined (CONFIG_BVME6000) +# define MACH_IS_BVME6000 (0) +#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ + || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) +# define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000) +#else +# define CONFIG_BVME6000_ONLY +# define MACH_IS_BVME6000 (1) +# define MACH_TYPE (MACH_BVME6000) +#endif + + #ifndef MACH_TYPE # define MACH_TYPE (m68k_machtype) #endif @@ -89,7 +131,7 @@ * * CPU_68020 == MMU_68851 * CPU_68030 == MMU_68030 - * CPU_68040 == FPU_68040 == MMU_68040 + * CPU_68040 == FPU_68040 == MMU_68040 (not strictly, think of 68LC040!) * CPU_68060 == FPU_68060 == MMU_68060 */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h --- v2.1.86/linux/include/asm-m68k/siginfo.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/siginfo.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,195 @@ +#ifndef _M68K_SIGINFO_H +#define _M68K_SIGINFO_H + +#include + +/* This is copied from asm-alpha/siginfo.h. */ + +typedef union sigval { + int sival_int; + void *sival_ptr; +} sigval_t; + +#define SI_MAX_SIZE 128 +#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 3) + +typedef struct siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + int _status; /* exit code */ + clock_t _utime; + clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + void *_addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} siginfo_t; + +/* + * How these fields are to be accessed. + */ +#define si_pid _sifields._kill._pid +#define si_uid _sifields._kill._uid +#define si_status _sifields._sigchld._status +#define si_utime _sifields._sigchld._utime +#define si_stime _sifields._sigchld._stime +#define si_value _sifields._rt._sigval +#define si_int _sifields._rt._sigval.sival_int +#define si_ptr _sifields._rt._sigval.sival_ptr +#define si_addr _sifields._sigfault._addr +#define si_band _sifields._sigpoll._band +#define si_fd _sifields._sigpoll._fd + +/* + * si_code values + * Digital reserves positive values for kernel-generated signals. + */ +#define SI_USER 0 /* sent by kill, sigsend, raise */ +#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define SI_QUEUE -1 /* sent by sigqueue */ +#define SI_TIMER -2 /* sent by timer expiration */ +#define SI_MESGQ -3 /* sent by real time mesq state change */ +#define SI_ASYNCIO -4 /* sent by AIO completion */ + +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) + +/* + * SIGILL si_codes + */ +#define ILL_ILLOPC 1 /* illegal opcode */ +#define ILL_ILLOPN 2 /* illegal operand */ +#define ILL_ILLADR 3 /* illegal addressing mode */ +#define ILL_ILLTRP 4 /* illegal trap */ +#define ILL_PRVOPC 5 /* privileged opcode */ +#define ILL_PRVREG 6 /* privileged register */ +#define ILL_COPROC 7 /* coprocessor error */ +#define ILL_BADSTK 8 /* internal stack error */ +#define NSIGILL 8 + +/* + * SIGFPE si_codes + */ +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ +#define NSIGFPE 8 + +/* + * SIGSEGV si_codes + */ +#define SEGV_MAPERR 1 /* address not mapped to object */ +#define SEGV_ACCERR 2 /* invalid permissions for mapped object */ +#define NSIGSEGV 2 + +/* + * SIGBUS si_codes + */ +#define BUS_ADRALN 1 /* invalid address alignment */ +#define BUS_ADRERR 2 /* non-existant physical address */ +#define BUS_OBJERR 3 /* object specific hardware error */ +#define NSIGBUS 3 + +/* + * SIGTRAP si_codes + */ +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ +#define NSIGTRAP 2 + +/* + * SIGCHLD si_codes + */ +#define CLD_EXITED 1 /* child has exited */ +#define CLD_KILLED 2 /* child was killed */ +#define CLD_DUMPED 3 /* child terminated abnormally */ +#define CLD_TRAPPED 4 /* traced child has trapped */ +#define CLD_STOPPED 5 /* child has stopped */ +#define CLD_CONTINUED 6 /* stopped child has continued */ +#define NSIGCHLD 6 + +/* + * SIGPOLL si_codes + */ +#define POLL_IN 1 /* data input available */ +#define POLL_OUT 2 /* output buffers available */ +#define POLL_MSG 3 /* input message available */ +#define POLL_ERR 4 /* i/o error */ +#define POLL_PRI 5 /* high priority input available */ +#define POLL_HUP 6 /* device disconnected */ +#define NSIGPOLL 6 + +/* + * sigevent definitions + * + * It seems likely that SIGEV_THREAD will have to be handled from + * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the + * thread manager then catches and does the appropriate nonsense. + * However, everything is written out here so as to not get lost. + */ +#define SIGEV_SIGNAL 0 /* notify via signal */ +#define SIGEV_NONE 1 /* other notification: meaningless */ +#define SIGEV_THREAD 2 /* deliver via thread creation */ + +#define SIGEV_MAX_SIZE 64 +#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) + +typedef struct sigevent { + sigval_t sigev_value; + int sigev_signo; + int sigev_notify; + union { + int _pad[SIGEV_PAD_SIZE]; + + struct { + void (*_function)(sigval_t); + void *_attribute; /* really pthread_attr_t */ + } _sigev_thread; + } _sigev_un; +} sigevent_t; + +#define sigev_notify_function _sigev_un._sigev_thread._function +#define sigev_notify_attributes _sigev_un._sigev_thread._attribute + +#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/signal.h linux/include/asm-m68k/signal.h --- v2.1.86/linux/include/asm-m68k/signal.h Mon Apr 8 14:36:14 1996 +++ linux/include/asm-m68k/signal.h Thu Feb 12 16:30:13 1998 @@ -1,10 +1,32 @@ #ifndef _M68K_SIGNAL_H #define _M68K_SIGNAL_H -typedef unsigned long sigset_t; /* at least 32 bits */ +#include -#define _NSIG 32 -#define NSIG _NSIG +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifdef __KERNEL__ +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ #define SIGHUP 1 #define SIGINT 2 @@ -43,22 +65,36 @@ #define SIGPWR 30 #define SIGUNUSED 31 +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + /* - * sa_flags values: SA_STACK is not currently supported, but will allow the - * usage of signal stacks by using the (now obsolete) sa_restorer field in - * the sigaction structure as a stack pointer. This is now possible due to - * the changes in signal handling. LBT 010493. + * SA_FLAGS values: + * + * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). + * (++roman: SA_ONSTACK is supported on m68k) * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. */ -#define SA_NOCLDSTOP 1 -#define SA_SHIRQ 0x04000000 -#define SA_STACK 0x08000000 +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 #define SA_RESTART 0x10000000 -#define SA_INTERRUPT 0x20000000 -#define SA_NOMASK 0x40000000 -#define SA_ONESHOT 0x80000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ #ifdef __KERNEL__ /* @@ -66,9 +102,11 @@ * irq handling routines. * * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 #endif #define SIG_BLOCK 0 /* for blocking signals */ @@ -82,15 +120,85 @@ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ #define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ +#ifdef __KERNEL__ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + struct sigaction { __sighandler_t sa_handler; sigset_t sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); }; +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; #ifdef __KERNEL__ #include -#endif + +#define __HAVE_ARCH_SIG_BITOPS + +extern __inline__ void sigaddset(sigset_t *set, int _sig) +{ + __asm__("bfset %0{%1,#1}" : "=m" (*set) : "id" ((_sig - 1) ^ 31) + : "cc"); +} + +extern __inline__ void sigdelset(sigset_t *set, int _sig) +{ + __asm__("bfclr %0{%1,#1}" : "=m"(*set) : "id"((_sig - 1) ^ 31) + : "cc"); +} + +extern __inline__ int __const_sigismember(sigset_t *set, int _sig) +{ + unsigned long sig = _sig - 1; + return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); +} + +extern __inline__ int __gen_sigismember(sigset_t *set, int _sig) +{ + char ret; + __asm__("bftst %1{%2,#1}\n\t sne %0" + : "=rm"(ret) : "m"(*set), "id"((_sig-1) ^ 31) : "cc"); + return ret; +} + +#define sigismember(set,sig) \ + (__builtin_constant_p(sig) ? \ + __const_sigismember(set,sig) : \ + __gen_sigismember(set,sig)) + +#define sigmask(sig) (1UL << ((sig) - 1)) + +extern __inline__ int sigfindinword(unsigned long word) +{ + __asm__("bfffo %1{#0,#0},%0" : "=d"(word) : "d"(word & -word) : "cc"); + return word ^ 31; +} + +#endif /* __KERNEL__ */ #endif /* _M68K_SIGNAL_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/socket.h linux/include/asm-m68k/socket.h --- v2.1.86/linux/include/asm-m68k/socket.h Thu Mar 27 14:40:07 1997 +++ linux/include/asm-m68k/socket.h Thu Feb 12 16:30:13 1998 @@ -33,4 +33,10 @@ #define SO_SECURITY_ENCRYPTION_TRANSPORT 23 #define SO_SECURITY_ENCRYPTION_NETWORK 24 +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + #endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/softirq.h linux/include/asm-m68k/softirq.h --- v2.1.86/linux/include/asm-m68k/softirq.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/softirq.h Thu Feb 12 16:30:13 1998 @@ -44,22 +44,22 @@ bh_mask &= ~(1 << nr); } -extern int __m68k_bh_counter; +extern unsigned int local_bh_count[NR_CPUS]; extern inline void start_bh_atomic(void) { - __m68k_bh_counter++; + local_bh_count[smp_processor_id()]++; barrier(); } extern inline void end_bh_atomic(void) { barrier(); - __m68k_bh_counter--; + local_bh_count[smp_processor_id()]--; } /* These are for the irq's testing the lock */ -#define softirq_trylock() (__m68k_bh_counter ? 0 : (__m68k_bh_counter=1)) -#define softirq_endlock() (__m68k_bh_counter = 0) +#define softirq_trylock(cpu) (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1)) +#define softirq_endlock(cpu) (local_bh_count[cpu] = 0) #endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h --- v2.1.86/linux/include/asm-m68k/system.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/system.h Thu Feb 12 16:30:13 1998 @@ -8,15 +8,12 @@ extern inline unsigned long rdusp(void) { unsigned long usp; - __asm__ __volatile__("movec %/usp,%0" - : "=d" (usp)); + __asm__ __volatile__("move %/usp,%0" : "=a" (usp)); return usp; } extern inline void wrusp(unsigned long usp) { - __asm__ __volatile__("movec %0,%/usp" - : - : "d" (usp)); + __asm__ __volatile__("move %0,%/usp" : : "a" (usp)); } /* @@ -63,7 +60,7 @@ struct __xchg_dummy { unsigned long a[100]; }; #define __xg(x) ((volatile struct __xchg_dummy *)(x)) -#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) +#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES) /* block out HSYNC on the atari */ #define __sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory") #else /* portable version */ diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ucontext.h linux/include/asm-m68k/ucontext.h --- v2.1.86/linux/include/asm-m68k/ucontext.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/ucontext.h Thu Feb 12 16:30:13 1998 @@ -0,0 +1,32 @@ +#ifndef _M68K_UCONTEXT_H +#define _M68K_UCONTEXT_H + +typedef int greg_t; +#define NGREG 18 +typedef greg_t gregset_t[NGREG]; + +typedef struct fpregset { + int f_pcr; + int f_psr; + int f_fpiaddr; + int f_fpregs[8][3]; +} fpregset_t; + +struct mcontext { + int version; + gregset_t gregs; + fpregset_t fpregs; +}; + +#define MCONTEXT_VERSION 2 + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct mcontext uc_mcontext; + unsigned long uc_filler[80]; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h --- v2.1.86/linux/include/asm-m68k/unistd.h Mon Dec 1 11:15:39 1997 +++ linux/include/asm-m68k/unistd.h Thu Feb 12 16:30:13 1998 @@ -174,9 +174,19 @@ #define __NR_query_module 167 #define __NR_poll 168 #define __NR_nfsservctl 169 -#define __NR_prctl 170 -#define __NR_pread 171 -#define __NR_pwrite 172 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread 180 +#define __NR_pwrite 181 +#define __NR_lchown 182 /* user-visible error numbers are in the range -1 - -122: see */ @@ -319,7 +329,7 @@ { register long retval __asm__ ("d0") = __NR_clone; register long clone_arg __asm__ ("d1") = flags | CLONE_VM; - unsigned long fs; + mm_segment_t fs; fs = get_fs(); set_fs (KERNEL_DS); diff -u --recursive --new-file v2.1.86/linux/include/asm-mips/ioctls.h linux/include/asm-mips/ioctls.h --- v2.1.86/linux/include/asm-mips/ioctls.h Fri Jan 23 18:10:32 1998 +++ linux/include/asm-mips/ioctls.h Thu Feb 12 16:25:04 1998 @@ -99,6 +99,8 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define TIOCSERCONFIG 0x5488 #define TIOCSERGWILD 0x5489 diff -u --recursive --new-file v2.1.86/linux/include/asm-ppc/ioctls.h linux/include/asm-ppc/ioctls.h --- v2.1.86/linux/include/asm-ppc/ioctls.h Thu Dec 4 13:09:01 1997 +++ linux/include/asm-ppc/ioctls.h Thu Feb 12 16:25:04 1998 @@ -86,6 +86,8 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -u --recursive --new-file v2.1.86/linux/include/asm-sparc/ioctls.h linux/include/asm-sparc/ioctls.h --- v2.1.86/linux/include/asm-sparc/ioctls.h Thu Dec 4 13:09:01 1997 +++ linux/include/asm-sparc/ioctls.h Thu Feb 12 16:25:04 1998 @@ -75,6 +75,9 @@ #define TIOCGPGRP _IOR('t', 131, int) #define TIOCSCTTY _IO('t', 132) #define TIOCGSID _IOR('t', 133, int) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */ +#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */ /* Little f */ #define FIOCLEX _IO('f', 1) diff -u --recursive --new-file v2.1.86/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h --- v2.1.86/linux/include/asm-sparc64/ioctls.h Mon Jan 12 15:15:58 1998 +++ linux/include/asm-sparc64/ioctls.h Thu Feb 12 16:25:04 1998 @@ -76,6 +76,9 @@ #define TIOCGPGRP _IOR('t', 131, int) #define TIOCSCTTY _IO('t', 132) #define TIOCGSID _IOR('t', 133, int) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */ +#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */ /* Little f */ #define FIOCLEX _IO('f', 1) diff -u --recursive --new-file v2.1.86/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.1.86/linux/include/linux/blk.h Fri Feb 6 15:32:55 1998 +++ linux/include/linux/blk.h Thu Feb 12 16:21:32 1998 @@ -5,6 +5,15 @@ #include #include +#include + +/* + * Spinlock for protecting the request queue which + * is mucked around with in interrupts on potentially + * multiple CPU's.. + */ +extern spinlock_t current_lock; + /* * NR_REQUEST is the number of entries in the request-queue. * NOTE that writes may use only the low 2/3 of these: reads diff -u --recursive --new-file v2.1.86/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.86/linux/include/linux/pci.h Fri Jan 30 11:28:10 1998 +++ linux/include/linux/pci.h Thu Feb 12 15:03:09 1998 @@ -281,6 +281,10 @@ #define PCI_DEVICE_ID_VLSI_82C597 0x0009 #define PCI_DEVICE_ID_VLSI_82C541 0x000c #define PCI_DEVICE_ID_VLSI_82C543 0x000d +#define PCI_DEVICE_ID_VLSI_82C532 0x0101 +#define PCI_DEVICE_ID_VLSI_82C534 0x0102 +#define PCI_DEVICE_ID_VLSI_82C535 0x0104 +#define PCI_DEVICE_ID_VLSI_82C147 0x0105 #define PCI_DEVICE_ID_VLSI_VAS96011 0x0702 #define PCI_VENDOR_ID_ADL 0x1005 @@ -311,6 +315,7 @@ #define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 #define PCI_DEVICE_ID_DEC_21142 0x0019 #define PCI_DEVICE_ID_DEC_21052 0x0021 +#define PCI_DEVICE_ID_DEC_21150 0x0022 #define PCI_DEVICE_ID_DEC_21152 0x0024 #define PCI_VENDOR_ID_CIRRUS 0x1013 @@ -333,7 +338,10 @@ #define PCI_DEVICE_ID_IBM_FIRE_CORAL 0x000a #define PCI_DEVICE_ID_IBM_TR 0x0018 #define PCI_DEVICE_ID_IBM_82G2675 0x001d +#define PCI_DEVICE_ID_IBM_MCA 0x0020 #define PCI_DEVICE_ID_IBM_82351 0x0022 +#define PCI_DEVICE_ID_IBM_SERVERAID 0x002e +#define PCI_DEVICE_ID_IBM_MPEG2 0x007d #define PCI_VENDOR_ID_WD 0x101c #define PCI_DEVICE_ID_WD_7197 0x3296 @@ -343,6 +351,7 @@ #define PCI_DEVICE_ID_AMD_SCSI 0x2020 #define PCI_VENDOR_ID_TRIDENT 0x1023 +#define PCI_DEVICE_ID_TRIDENT_9397 0x9397 #define PCI_DEVICE_ID_TRIDENT_9420 0x9420 #define PCI_DEVICE_ID_TRIDENT_9440 0x9440 #define PCI_DEVICE_ID_TRIDENT_9660 0x9660 @@ -356,6 +365,7 @@ #define PCI_DEVICE_ID_MATROX_MIL 0x0519 #define PCI_DEVICE_ID_MATROX_MYS 0x051A #define PCI_DEVICE_ID_MATROX_MIL_2 0x051b +#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f #define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10 #define PCI_VENDOR_ID_CT 0x102c @@ -376,8 +386,8 @@ #define PCI_VENDOR_ID_SI 0x1039 #define PCI_DEVICE_ID_SI_6201 0x0001 #define PCI_DEVICE_ID_SI_6202 0x0002 -#define PCI_DEVICE_ID_SI_6205 0x0205 #define PCI_DEVICE_ID_SI_503 0x0008 +#define PCI_DEVICE_ID_SI_6205 0x0205 #define PCI_DEVICE_ID_SI_501 0x0406 #define PCI_DEVICE_ID_SI_496 0x0496 #define PCI_DEVICE_ID_SI_601 0x0601 @@ -395,6 +405,9 @@ #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 #define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001 +#define PCI_DEVICE_ID_PCTECH_SAMURAI_0 0x3000 +#define PCI_DEVICE_ID_PCTECH_SAMURAI_1 0x3010 +#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020 #define PCI_VENDOR_ID_DPT 0x1044 #define PCI_DEVICE_ID_DPT 0xa400 @@ -408,6 +421,7 @@ #define PCI_DEVICE_ID_OPTI_82C701 0xc701 #define PCI_DEVICE_ID_OPTI_82C814 0xc814 #define PCI_DEVICE_ID_OPTI_82C822 0xc822 +#define PCI_DEVICE_ID_OPTI_82C825 0xd568 #define PCI_VENDOR_ID_SGS 0x104a #define PCI_DEVICE_ID_SGS_2000 0x0008 @@ -423,6 +437,7 @@ #define PCI_DEVICE_ID_TI_TVP4020 0x3d07 #define PCI_DEVICE_ID_TI_PCI1130 0xac12 #define PCI_DEVICE_ID_TI_PCI1131 0xac15 +#define PCI_DEVICE_ID_TI_PCI1250 0xac16 #define PCI_VENDOR_ID_OAK 0x104e #define PCI_DEVICE_ID_OAK_OTI107 0x0107 @@ -516,6 +531,8 @@ #define PCI_VENDOR_ID_BROOKTREE 0x109e #define PCI_DEVICE_ID_BROOKTREE_848 0x0350 +#define PCI_DEVICE_ID_BROOKTREE_849A 0x0351 +#define PCI_DEVICE_ID_BROOKTREE_8474 0x8474 #define PCI_VENDOR_ID_SIERRA 0x10a8 #define PCI_DEVICE_ID_SIERRA_STB 0x0000 @@ -531,6 +548,9 @@ #define PCI_VENDOR_ID_DATABOOK 0x10b3 #define PCI_DEVICE_ID_DATABOOK_87144 0xb106 +#define PCI_VENDOR_ID_PLX 0x10b5 +#define PCI_DEVICE_ID_PLX_9080 0x9080 + #define PCI_VENDOR_ID_3COM 0x10b7 #define PCI_DEVICE_ID_3COM_3C590 0x5900 #define PCI_DEVICE_ID_3COM_3C595TX 0x5950 @@ -555,9 +575,11 @@ #define PCI_DEVICE_ID_AL_M1523 0x1523 #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 +#define PCI_DEVICE_ID_AL_M3307 0x3307 #define PCI_DEVICE_ID_AL_M4803 0x5215 #define PCI_DEVICE_ID_AL_M5219 0x5219 #define PCI_DEVICE_ID_AL_M5229 0x5229 +#define PCI_DEVICE_ID_AL_M5237 0x5237 #define PCI_VENDOR_ID_MITSUBISHI 0x10ba @@ -573,6 +595,7 @@ #define PCI_VENDOR_ID_ASP 0x10cd #define PCI_DEVICE_ID_ASP_ABP940 0x1200 #define PCI_DEVICE_ID_ASP_ABP940U 0x1300 +#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300 #define PCI_VENDOR_ID_CERN 0x10dc #define PCI_DEVICE_ID_CERN_SPSB_PMC 0x0001 @@ -607,6 +630,7 @@ #define PCI_VENDOR_ID_INIT 0x1101 #define PCI_DEVICE_ID_INIT_320P 0x9100 +#define PCI_DEVICE_ID_INIT_360P 0x9500 #define PCI_VENDOR_ID_VIA 0x1106 #define PCI_DEVICE_ID_VIA_82C505 0x0505 @@ -616,11 +640,13 @@ #define PCI_DEVICE_ID_VIA_82C585 0x0585 #define PCI_DEVICE_ID_VIA_82C586_0 0x0586 #define PCI_DEVICE_ID_VIA_82C595 0x0595 +#define PCI_DEVICE_ID_VIA_82C597_0 0x0597 #define PCI_DEVICE_ID_VIA_82C926 0x0926 #define PCI_DEVICE_ID_VIA_82C416 0x1571 #define PCI_DEVICE_ID_VIA_82C595_97 0x1595 #define PCI_DEVICE_ID_VIA_82C586_2 0x3038 #define PCI_DEVICE_ID_VIA_82C586_3 0x3040 +#define PCI_DEVICE_ID_VIA_82C597_1 0x8597 #define PCI_VENDOR_ID_VORTEX 0x1119 #define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000 @@ -670,8 +696,8 @@ #define PCI_VENDOR_ID_PHILIPS 0x1131 #define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146 -#define PCI_VENDOR_ID_PLX 0x113c -#define PCI_DEVICE_ID_PLX_9060 0x0001 +#define PCI_VENDOR_ID_CYCLONE 0x113c +#define PCI_DEVICE_ID_CYCLONE_SDK 0x0001 #define PCI_VENDOR_ID_ALLIANCE 0x1142 #define PCI_DEVICE_ID_ALLIANCE_PROMOTIO 0x3210 @@ -683,7 +709,13 @@ #define PCI_DEVICE_ID_VMIC_VME 0x7587 #define PCI_VENDOR_ID_DIGI 0x114f +#define PCI_DEVICE_ID_DIGI_EPC 0x0002 #define PCI_DEVICE_ID_DIGI_RIGHTSWITCH 0x0003 +#define PCI_DEVICE_ID_DIGI_XEM 0x0004 +#define PCI_DEVICE_ID_DIGI_XR 0x0005 +#define PCI_DEVICE_ID_DIGI_CX 0x0006 +#define PCI_DEVICE_ID_DIGI_XRJ 0x0009 +#define PCI_DEVICE_ID_DIGI_EPCJ 0x000a #define PCI_VENDOR_ID_MUTECH 0x1159 #define PCI_DEVICE_ID_MUTECH_MV1000 0x0001 @@ -694,10 +726,15 @@ #define PCI_VENDOR_ID_TOSHIBA 0x1179 #define PCI_DEVICE_ID_TOSHIBA_601 0x0601 +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a +#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f #define PCI_VENDOR_ID_RICOH 0x1180 #define PCI_DEVICE_ID_RICOH_RL5C466 0x0466 +#define PCI_VENDOR_ID_ARTOP 0x1191 +#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005 + #define PCI_VENDOR_ID_ZEITNET 0x1193 #define PCI_DEVICE_ID_ZEITNET_1221 0x0001 #define PCI_DEVICE_ID_ZEITNET_1225 0x0002 @@ -711,6 +748,9 @@ #define PCI_VENDOR_ID_NP 0x11bc #define PCI_DEVICE_ID_NP_PCI_FDDI 0x0001 +#define PCI_VENDOR_ID_ATT 0x11c1 +#define PCI_DEVICE_ID_ATT_L56XMF 0x0440 + #define PCI_VENDOR_ID_SPECIALIX 0x11cb #define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000 #define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 @@ -742,17 +782,20 @@ #define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 #define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 +#define PCI_VENDOR_ID_O2 0x1217 +#define PCI_DEVICE_ID_O2_6832 0x6832 + #define PCI_VENDOR_ID_3DFX 0x121a #define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 +#define PCI_VENDOR_ID_SIGMADES 0x1236 +#define PCI_DEVICE_ID_SIGMADES_6425 0x6401 + #define PCI_VENDOR_ID_STALLION 0x124d #define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000 #define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002 #define PCI_DEVICE_ID_STALLION_EIOPCI 0x0003 -#define PCI_VENDOR_ID_SIGMADES 0x1236 -#define PCI_DEVICE_ID_SIGMADES_6425 0x6401 - #define PCI_VENDOR_ID_OPTIBASE 0x1255 #define PCI_DEVICE_ID_OPTIBASE_FORGE 0x1110 #define PCI_DEVICE_ID_OPTIBASE_FUSION 0x1210 @@ -809,6 +852,7 @@ #define PCI_DEVICE_ID_S3_ViRGE_MX 0x8c01 #define PCI_DEVICE_ID_S3_ViRGE_MXP 0x8c02 #define PCI_DEVICE_ID_S3_ViRGE_MXPMV 0x8c03 +#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_82375 0x0482 diff -u --recursive --new-file v2.1.86/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.1.86/linux/include/linux/tty.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/tty.h Thu Feb 12 16:25:04 1998 @@ -282,6 +282,7 @@ #define TTY_CLOSING 7 #define TTY_HW_COOK_OUT 14 #define TTY_HW_COOK_IN 15 +#define TTY_PTY_LOCK 16 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) diff -u --recursive --new-file v2.1.86/linux/include/linux/tty_driver.h linux/include/linux/tty_driver.h --- v2.1.86/linux/include/linux/tty_driver.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/tty_driver.h Thu Feb 12 16:25:04 1998 @@ -213,6 +213,7 @@ #define SYSTEM_TYPE_TTY 0x0001 #define SYSTEM_TYPE_CONSOLE 0x0002 #define SYSTEM_TYPE_SYSCONS 0x0003 +#define SYSTEM_TYPE_SYSPTMX 0x0004 /* pty subtypes (magic, used by tty_io.c) */ #define PTY_TYPE_MASTER 0x0001 diff -u --recursive --new-file v2.1.86/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h --- v2.1.86/linux/include/linux/ufs_fs.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/ufs_fs.h Thu Feb 12 16:27:15 1998 @@ -9,6 +9,13 @@ * Clean swab support by Fare * just hope no one is using NNUUXXI on __?64 structure elements * 64-bit clean thanks to Maciej W. Rozycki + * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . + * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen . */ #ifndef __LINUX_UFS_FS_H @@ -49,13 +56,45 @@ #define UFS_FSACTIVE ((char)0x00) #define UFS_FSCLEAN ((char)0x01) #define UFS_FSSTABLE ((char)0x02) +#define UFS_FSOSF1 ((char)0x03) /* is this correct for DEC OSF/1? */ #define UFS_FSBAD ((char)0xff) -/* Flags for ufs_sb_info */ -#define UFS_DEBUG 0x00000001 -#define UFS_DEBUG_INODE 0x00000002 -#define UFS_DEBUG_NAMEI 0x00000004 -#define UFS_DEBUG_LINKS 0x00000008 +/* From here to next blank line, s_flags for ufs_sb_info */ +/* endianness */ +#define UFS_BYTESEX 0x00000001 /* mask; leave room to 0xF */ +#define UFS_LITTLE_ENDIAN 0x00000000 +#define UFS_BIG_ENDIAN 0x00000001 +/* directory entry encoding */ +#define UFS_DE_MASK 0x00000010 /* mask for the following */ +#define UFS_DE_OLD 0x00000000 +#define UFS_DE_44BSD 0x00000010 +/* uid encoding */ +#define UFS_UID_MASK 0x00000060 /* mask for the following */ +#define UFS_UID_OLD 0x00000000 +#define UFS_UID_44BSD 0x00000020 +#define UFS_UID_EFT 0x00000040 +/* superblock state encoding */ +#define UFS_ST_MASK 0x00000700 /* mask for the following */ +#define UFS_ST_OLD 0x00000000 +#define UFS_ST_44BSD 0x00000100 +#define UFS_ST_SUN 0x00000200 +#define UFS_ST_NEXT 0x00000400 +/* filesystem flavors (combo of features) */ +#define UFS_FEATURES 0x00FFFFF0 /* room for extension */ +#define UFS_VANILLA 0x00000000 +#define UFS_OLD 0x00000000 /* 4.2BSD */ +#define UFS_44BSD 0x00000130 +#define UFS_HURD 0x00000130 +#define UFS_SUN 0x00000200 +#define UFS_NEXT 0x00000400 +/* we preserve distinction in flavor identification even without difference, + * because yet-to-be-supported features may introduce difference in the future + */ +/* last but not least, debug flags */ +#define UFS_DEBUG 0x01000000 +#define UFS_DEBUG_INODE 0x02000000 +#define UFS_DEBUG_NAMEI 0x04000000 +#define UFS_DEBUG_LINKS 0x08000000 #ifdef UFS_HEAVY_DEBUG # define UFS_DEBUG_INITIAL UFS_DEBUG @@ -63,10 +102,9 @@ # define UFS_DEBUG_INITIAL 0 #endif -/* (!) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes */ -#define UFS_LITTLE_ENDIAN 0x00000000 /* 0x00010000 */ -#define UFS_BIG_ENDIAN 0x00010000 /* 0x00020000 */ -#define UFS_BYTESEX 0x00010000 /* 0x00030000 */ +/* fs_inodefmt options */ +#define UFS_42INODEFMT -1 +#define UFS_44INODEFMT 2 #define UFS_ADDR_PER_BLOCK(sb) ((sb)->u.ufs_sb.s_bsize >> 2) #define UFS_ADDR_PER_BLOCK_BITS(sb) ((sb)->u.ufs_sb.s_bshift - 2) @@ -87,6 +125,12 @@ /* XXX - this can be optimized if s_ipg is a power of 2. */ #define ufs_ino2cg(inode) ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg) +/* current filesystem state; method depends on flags */ +#define UFS_STATE(usb) \ + ( ((flags&UFS_ST_MASK) == UFS_ST_OLD) \ + ? (usb)->fs_u.fs_sun.fs_state /* old normal way */ \ + : (usb)->fs_u.fs_44.fs_state /* 4.4BSD way */ ) + #define UFS_MAXNAMLEN 255 #define ufs_lbn(sb, block) ((block) >> (sb)->u.ufs_sb.s_lshift) @@ -101,8 +145,14 @@ struct ufs_direct { __u32 d_ino; /* inode number of this entry */ __u16 d_reclen; /* length of this entry */ - __u16 d_namlen; /* actual length of d_name */ - char d_name[UFS_MAXNAMLEN + 1]; /* file name */ + union { + __u16 d_namlen; /* actual length of d_name */ + struct { + __u8 d_type; /* file type */ + __u8 d_namlen; /* length of string in d_name */ + } d_44; + } d_u; + __u8 d_name[UFS_MAXNAMLEN + 1]; /* file name */ }; #define MAXMNTLEN 512 @@ -193,10 +243,24 @@ __u32 fs_csp[MAXCSBUFS]; /* list of fs_cs info buffers */ __u32 fs_cpc; /* cyl per cycle in postbl */ __u16 fs_opostbl[16][8]; /* old rotation block list head */ - __s32 fs_sparecon[55]; /* reserved for future constants */ - __s32 fs_state; /* file system state time stamp */ - __u32 fs_qbmask[2]; /* ~usb_bmask */ - __u32 fs_qfmask[2]; /* ~usb_fmask */ + union { + struct { + __s32 fs_sparecon[55];/* reserved for future constants */ + __s32 fs_state; /* file system state time stamp */ + __u32 fs_qbmask[2]; /* ~usb_bmask */ + __u32 fs_qfmask[2]; /* ~usb_fmask */ + } fs_sun; + struct { + __s32 fs_sparecon[50];/* reserved for future constants */ + __s32 fs_contigsumsize;/* size of cluster summary array */ + __s32 fs_maxsymlinklen;/* max length of an internal symlink */ + __s32 fs_inodefmt; /* format of on-disk inodes */ + __u64 fs_maxfilesize; /* max representable file size */ + __u32 fs_qbmask[2]; /* ~usb_bmask */ + __u32 fs_qfmask[2]; /* ~usb_fmask */ + __s32 fs_state; /* file system state time stamp */ + } fs_44; + } fs_u; __s32 fs_postblformat; /* format of positional layout tables */ __s32 fs_nrpos; /* number of rotational positions */ __s32 fs_postbloff; /* (__s16) rotation block list head */ @@ -211,24 +275,50 @@ struct ufs_inode { __u16 ui_mode; /* 0x0 */ __u16 ui_nlink; /* 0x2 */ - __u16 ui_suid; /* 0x4 */ - __u16 ui_sgid; /* 0x6 */ + union { + struct { + __u16 suid; /* 0x4 */ + __u16 sgid; /* 0x6 */ + } oldids; + __u32 inumber; /* 0x4 lsf: inode number */ + __u32 author; /* 0x4 GNU HURD: author */ + } ui_u1; __u64 ui_size; /* 0x8 */ struct ufs_timeval ui_atime; /* 0x10 access */ struct ufs_timeval ui_mtime; /* 0x18 modification */ struct ufs_timeval ui_ctime; /* 0x20 creation */ - __u32 ui_db[UFS_NDADDR]; /* 0x28 data blocks */ - __u32 ui_ib[UFS_NINDIR]; /* 0x58 indirect blocks */ + union { + struct { + __u32 ui_db[UFS_NDADDR];/* 0x28 data blocks */ + __u32 ui_ib[UFS_NINDIR];/* 0x58 indirect blocks */ + } ui_addr; + __u8 ui_symlink[4*(UFS_NDADDR+UFS_NINDIR)];/* 0x28 fast symlink */ + } ui_u2; __u32 ui_flags; /* 0x64 unused -- "status flags (chflags)" ??? */ __u32 ui_blocks; /* 0x68 blocks in use */ __u32 ui_gen; /* 0x6c generation number XXX - what is this? */ - __u32 ui_shadow; /* 0x70 shadow inode XXX - what is this?*/ - __u32 ui_uid; /* 0x74 long EFT version of uid */ - __u32 ui_gid; /* 0x78 long EFT version of gid */ - __u32 ui_oeftflag; /* 0x7c reserved */ + union { + struct { + __u32 ui_shadow;/* 0x70 shadow inode XXX - what is this?*/ + __u32 ui_uid; /* 0x74 long EFT version of uid */ + __u32 ui_gid; /* 0x78 long EFT version of gid */ + __u32 ui_oeftflag;/* 0x7c reserved */ + } ui_sun; + struct { + __u32 ui_uid; /* 0x70 File owner */ + __u32 ui_gid; /* 0x74 File group */ + __s32 ui_spare[2];/* 0x78 reserved */ + } ui_44; + struct { + __u32 ui_uid; /* 0x70 */ + __u32 ui_gid; /* 0x74 */ + __u16 ui_modeh;/* 0x78 mode high bits */ + __u16 ui_spare;/* 0x7A unused */ + __u32 ui_trans;/* 0x7c filesystem translator */ + } ui_hurd; + } ui_u3; }; - - + #ifdef __KERNEL__ /* * Function prototypes diff -u --recursive --new-file v2.1.86/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h --- v2.1.86/linux/include/linux/ufs_fs_i.h Thu Oct 3 00:35:01 1996 +++ linux/include/linux/ufs_fs_i.h Thu Feb 12 16:27:15 1998 @@ -8,13 +8,18 @@ * * $Id: ufs_fs_i.h,v 1.2 1996/05/03 04:02:25 davem Exp $ * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen . */ #ifndef _LINUX_UFS_FS_I_H #define _LINUX_UFS_FS_I_H struct ufs_inode_info { - __u32 i_data[15]; + union { + __u32 i_data[15]; + __u8 i_symlink[4*15]; /* fast symlink */ + } i_u1; __u64 i_size; __u32 i_flags; __u32 i_gen; diff -u --recursive --new-file v2.1.86/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h --- v2.1.86/linux/include/linux/ufs_fs_sb.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/ufs_fs_sb.h Thu Feb 12 16:27:15 1998 @@ -8,6 +8,8 @@ * * $Id: ufs_fs_sb.h,v 1.6 1996/06/01 15:31:08 ecd Exp $ * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen . */ #ifndef __LINUX_UFS_FS_SB_H @@ -35,6 +37,7 @@ __u32 s_lshift; __u32 s_lmask; __u32 s_fsfrag; + __u32 s_blockbase; /* offset of NeXTstep superblock */ }; #endif /* __LINUX_UFS_FS_SB_H */ diff -u --recursive --new-file v2.1.86/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h --- v2.1.86/linux/include/linux/umsdos_fs.h Fri Feb 6 15:34:49 1998 +++ linux/include/linux/umsdos_fs.h Thu Feb 12 16:23:27 1998 @@ -4,6 +4,8 @@ #define UMSDOS_VERSION 0 #define UMSDOS_RELEASE 4 +#define UMSDOS_ROOT_INO 1 + /* This is the file acting as a directory extension */ #define UMSDOS_EMD_FILE "--linux-.---" #define UMSDOS_EMD_NAMELEN 12 @@ -20,32 +22,34 @@ #include #endif + struct umsdos_fake_info { - char fname[13]; - int len; + char fname[13]; + int len; }; #define UMSDOS_MAXNAME 220 /* This structure is 256 bytes large, depending on the name, only part */ /* of it is written to disk */ +/* nice though it would be, I can't change this and preserve backward compatibility */ struct umsdos_dirent { - unsigned char name_len; /* if == 0, then this entry is not used */ - unsigned char flags; /* UMSDOS_xxxx */ - unsigned short nlink; /* How many hard links point to this entry */ - uid_t uid; /* Owner user id */ - gid_t gid; /* Group id */ - time_t atime; /* Access time */ - time_t mtime; /* Last modification time */ - time_t ctime; /* Creation time */ - dev_t rdev; /* major and minor number of a device */ - /* special file */ - umode_t mode; /* Standard UNIX permissions bits + type of */ - char spare[12]; /* unused bytes for future extensions */ - /* file, see linux/stat.h */ - char name[UMSDOS_MAXNAME]; /* Not '\0' terminated */ - /* but '\0' padded, so it will allow */ - /* for adding news fields in this record */ - /* by reducing the size of name[] */ + unsigned char name_len; /* if == 0, then this entry is not used */ + unsigned char flags; /* UMSDOS_xxxx */ + unsigned short nlink; /* How many hard links point to this entry */ + uid_t uid; /* Owner user id */ + gid_t gid; /* Group id */ + time_t atime; /* Access time */ + time_t mtime; /* Last modification time */ + time_t ctime; /* Creation time */ + dev_t rdev; /* major and minor number of a device */ + /* special file */ + umode_t mode; /* Standard UNIX permissions bits + type of */ + char spare[12]; /* unused bytes for future extensions */ + /* file, see linux/stat.h */ + char name[UMSDOS_MAXNAME]; /* Not '\0' terminated */ + /* but '\0' padded, so it will allow */ + /* for adding news fields in this record */ + /* by reducing the size of name[] */ }; #define UMSDOS_HIDDEN 1 /* Never show this entry in directory search */ #define UMSDOS_HLINK 2 /* It is a (pseudo) hard link */ @@ -58,15 +62,16 @@ #define UMSDOS_REC_SIZE 64 /* Translation between MSDOS name and UMSDOS name */ + struct umsdos_info{ - int msdos_reject; /* Tell if the file name is invalid for MSDOS */ - /* See umsdos_parse */ - struct umsdos_fake_info fake; - struct umsdos_dirent entry; - off_t f_pos; /* offset of the entry in the EMD file */ - /* or offset where the entry may be store */ - /* if it is a new entry */ - int recsize; /* Record size needed to store entry */ + int msdos_reject; /* Tell if the file name is invalid for MSDOS */ + /* See umsdos_parse */ + struct umsdos_fake_info fake; + struct umsdos_dirent entry; + off_t f_pos; /* offset of the entry in the EMD file */ + /* or offset where the entry may be store */ + /* if it is a new entry */ + int recsize; /* Record size needed to store entry */ }; /* Definitions for ioctl (number randomly chosen) */ @@ -88,38 +93,39 @@ #define UMSDOS_RENAME_DOS _IO(0x04,220) /* rename a file/directory in the DOS */ /* directory only */ struct umsdos_ioctl{ - struct dirent dos_dirent; - struct umsdos_dirent umsdos_dirent; - /* The following structure is used to exchange some data */ - /* with utilities (umsdos_progs/util/umsdosio.c). The first */ - /* releases were using struct stat from "sys/stat.h". This was */ - /* causing some problem for cross compilation of the kernel */ - /* Since I am not really using the structure stat, but only some field */ - /* of it, I have decided to replicate the structure here */ - /* for compatibility with the binaries out there */ - struct { - dev_t st_dev; - unsigned short __pad1; - ino_t st_ino; - umode_t st_mode; - nlink_t st_nlink; - uid_t st_uid; - gid_t st_gid; - dev_t st_rdev; - unsigned short __pad2; - off_t st_size; - unsigned long st_blksize; - unsigned long st_blocks; - time_t st_atime; - unsigned long __unused1; - time_t st_mtime; - unsigned long __unused2; - time_t st_ctime; - unsigned long __unused3; - unsigned long __unused4; - unsigned long __unused5; - }stat; - char version,release; + struct dirent dos_dirent; + struct umsdos_dirent umsdos_dirent; + /* The following structure is used to exchange some data */ + /* with utilities (umsdos_progs/util/umsdosio.c). The first */ + /* releases were using struct stat from "sys/stat.h". This was */ + /* causing some problem for cross compilation of the kernel */ + /* Since I am not really using the structure stat, but only some field */ + /* of it, I have decided to replicate the structure here */ + /* for compatibility with the binaries out there */ + /* FIXME PTW 1998, this has probably changed */ + struct { + dev_t st_dev; + unsigned short __pad1; + ino_t st_ino; + umode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned short __pad2; + off_t st_size; + unsigned long st_blksize; + unsigned long st_blocks; + time_t st_atime; + unsigned long __unused1; + time_t st_mtime; + unsigned long __unused2; + time_t st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; + }stat; + char version,release; }; /* Different macros to access struct umsdos_dirent */ @@ -135,7 +141,6 @@ extern struct file_operations umsdos_file_operations; extern struct inode_operations umsdos_file_inode_operations; extern struct inode_operations umsdos_file_inode_operations_no_bmap; -extern struct inode_operations umsdos_file_inode_operations_readpage; extern struct inode_operations umsdos_symlink_inode_operations; extern int init_umsdos_fs(void); diff -u --recursive --new-file v2.1.86/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p --- v2.1.86/linux/include/linux/umsdos_fs.p Mon Jun 16 16:36:00 1997 +++ linux/include/linux/umsdos_fs.p Thu Feb 12 13:36:57 1998 @@ -1,10 +1,10 @@ /* check.c 23/01/95 03.38.30 */ void check_page_tables (void); /* dir.c 22/06/95 00.22.12 */ -long UMSDOS_dir_read (struct inode *inode, - struct file *filp, +int UMSDOS_dir_read ( struct file *filp, char *buf, - unsigned long count); + size_t size, + loff_t *count); void umsdos_lookup_patch (struct inode *dir, struct inode *inode, struct umsdos_dirent *entry, @@ -13,29 +13,35 @@ struct inode *inode, struct umsdos_dirent *entry); int umsdos_locate_path (struct inode *inode, char *path); -int umsdos_is_pseudodos (struct inode *dir, const char *name, int len); -int UMSDOS_lookup (struct inode *dir, +int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); +int compat_UMSDOS_lookup (struct inode *dir, const char *name, int len, struct inode **result); +int UMSDOS_lookup(struct inode *dir,struct dentry *dentry); + int umsdos_hlink2inode (struct inode *hlink, struct inode **result); /* emd.c 22/06/95 00.22.04 */ -long umsdos_file_read_kmem (struct inode *inode, +ssize_t umsdos_file_read_kmem (struct inode *emd_dir, struct file *filp, char *buf, - unsigned long count); -long umsdos_file_write_kmem (struct inode *inode, + size_t count, + loff_t *offs); +ssize_t umsdos_file_write_kmem (struct inode *emd_dir, struct file *filp, const char *buf, - unsigned long count); -long umsdos_emd_dir_write (struct inode *emd_dir, + size_t count, + loff_t *offs); +ssize_t umsdos_emd_dir_write (struct inode *emd_dir, struct file *filp, char *buf, - unsigned long count); -long umsdos_emd_dir_read (struct inode *emd_dir, + size_t count, + loff_t *offs); +ssize_t umsdos_emd_dir_read (struct inode *emd_dir, struct file *filp, char *buf, - unsigned long count); + size_t count, + loff_t *loffs); struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat); int umsdos_emd_dir_readentry (struct inode *emd_dir, struct file *filp, @@ -57,13 +63,14 @@ /* inode.c 12/06/95 09.49.40 */ void UMSDOS_put_inode (struct inode *inode); void UMSDOS_put_super (struct super_block *sb); -void UMSDOS_statfs (struct super_block *sb, +int UMSDOS_statfs (struct super_block *sb, struct statfs *buf, int bufsiz); -int umsdos_real_lookup (struct inode *dir, +int compat_umsdos_real_lookup (struct inode *dir, const char *name, int len, struct inode **result); +int umsdos_real_lookup(struct inode *inode,struct dentry *dentry); void umsdos_setup_dir_inode (struct inode *inode); void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, @@ -75,7 +82,7 @@ int umsdos_get_dirowner (struct inode *inode, struct inode **result); void UMSDOS_read_inode (struct inode *inode); void UMSDOS_write_inode (struct inode *inode); -int UMSDOS_notify_change (struct inode *inode, struct iattr *attr); +int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr); struct super_block *UMSDOS_read_super (struct super_block *s, void *data, int silent); @@ -87,50 +94,40 @@ /* mangle.c 25/01/95 02.25.38 */ void umsdos_manglename (struct umsdos_info *info); int umsdos_evalrecsize (int len); -int umsdos_parse (const char *fname, int len, struct umsdos_info *info); +int umsdos_parse (const char *name,int len, struct umsdos_info *info); /* namei.c 25/01/95 02.25.38 */ void umsdos_lockcreate (struct inode *dir); void umsdos_startlookup (struct inode *dir); void umsdos_unlockcreate (struct inode *dir); void umsdos_endlookup (struct inode *dir); + int UMSDOS_symlink (struct inode *dir, - const char *name, - int len, - const char *symname); -int UMSDOS_link (struct inode *oldinode, - struct inode *dir, - const char *name, - int len); + struct dentry *dentry, + const char *symname); +int UMSDOS_link (struct dentry *olddentry, + struct inode *dir, + struct dentry *dentry); int UMSDOS_create (struct inode *dir, - const char *name, - int len, - int mode, - struct inode **result); + struct dentry *dentry, + int mode); + int UMSDOS_mkdir (struct inode *dir, - const char *name, - int len, - int mode); + struct dentry *dentry, + int mode); int UMSDOS_mknod (struct inode *dir, - const char *name, - int len, - int mode, - int rdev); -int UMSDOS_rmdir (struct inode *dir, const char *name, int len); -int UMSDOS_unlink (struct inode *dir, const char *name, int len); + struct dentry *dentry, + int mode, + int rdev); +int UMSDOS_rmdir (struct inode *dir,struct dentry *dentry); +int UMSDOS_unlink (struct inode *dir, struct dentry *dentry); int UMSDOS_rename (struct inode *old_dir, - const char *old_name, - int old_len, - struct inode *new_dir, - const char *new_name, - int new_len); + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry); /* rdir.c 22/03/95 03.31.42 */ int umsdos_rlookup_x (struct inode *dir, - const char *name, - int len, - struct inode **result, + struct dentry *dentry, int nopseudo); int UMSDOS_rlookup (struct inode *dir, - const char *name, - int len, - struct inode **result); + struct dentry *dentry); /* symlink.c 23/01/95 03.38.30 */ diff -u --recursive --new-file v2.1.86/linux/kernel/time.c linux/kernel/time.c --- v2.1.86/linux/kernel/time.c Mon Dec 8 23:58:05 1997 +++ linux/kernel/time.c Thu Feb 12 16:44:15 1998 @@ -216,32 +216,24 @@ /* adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. */ -asmlinkage int sys_adjtimex(struct timex *txc_p) +int do_adjtimex(struct timex *txc) { long ltemp, mtemp, save_adjust; - struct timex txc; /* Local copy of parameter */ - - /* Copy the user data space into the kernel copy - * structure. But bear in mind that the structures - * may change - */ - if(copy_from_user(&txc, txc_p, sizeof(struct timex))) - return -EFAULT; /* In order to modify anything, you gotta be super-user! */ - if (txc.modes && !suser()) + if (txc->modes && !suser()) return -EPERM; /* Now we validate the data before disabling interrupts */ - if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET)) + if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) /* adjustment Offset limited to +- .512 seconds */ - if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE ) + if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) return -EINVAL; /* if the quartz is off by more than 10% something is VERY wrong ! */ - if (txc.modes & ADJ_TICK) - if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ) + if (txc->modes & ADJ_TICK) + if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) return -EINVAL; cli(); /* SMP: global cli() is enough protection. */ @@ -250,37 +242,37 @@ save_adjust = time_adjust; /* If there are input parameters, then process them */ - if (txc.modes) + if (txc->modes) { if (time_state == TIME_BAD) time_state = TIME_OK; - if (txc.modes & ADJ_STATUS) - time_status = txc.status; + if (txc->modes & ADJ_STATUS) + time_status = txc->status; - if (txc.modes & ADJ_FREQUENCY) - time_freq = txc.freq; + if (txc->modes & ADJ_FREQUENCY) + time_freq = txc->freq; - if (txc.modes & ADJ_MAXERROR) - time_maxerror = txc.maxerror; + if (txc->modes & ADJ_MAXERROR) + time_maxerror = txc->maxerror; - if (txc.modes & ADJ_ESTERROR) - time_esterror = txc.esterror; + if (txc->modes & ADJ_ESTERROR) + time_esterror = txc->esterror; - if (txc.modes & ADJ_TIMECONST) - time_constant = txc.constant; + if (txc->modes & ADJ_TIMECONST) + time_constant = txc->constant; - if (txc.modes & ADJ_OFFSET) - if ((txc.modes == ADJ_OFFSET_SINGLESHOT) + if (txc->modes & ADJ_OFFSET) + if ((txc->modes == ADJ_OFFSET_SINGLESHOT) || !(time_status & STA_PLL)) { - time_adjust = txc.offset; + time_adjust = txc->offset; } else if ((time_status & STA_PLL)||(time_status & STA_PPSTIME)) { ltemp = (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) ? - pps_offset : txc.offset; + pps_offset : txc->offset; /* * Scale the phase adjustment and @@ -335,30 +327,46 @@ else if (time_freq < -time_tolerance) time_freq = -time_tolerance; } /* STA_PLL || STA_PPSTIME */ - if (txc.modes & ADJ_TICK) - tick = txc.tick; + if (txc->modes & ADJ_TICK) + tick = txc->tick; } - txc.offset = save_adjust; - txc.freq = time_freq; - txc.maxerror = time_maxerror; - txc.esterror = time_esterror; - txc.status = time_status; - txc.constant = time_constant; - txc.precision = time_precision; - txc.tolerance = time_tolerance; - txc.time = xtime; - txc.tick = tick; - txc.ppsfreq = pps_freq; - txc.jitter = pps_jitter; - txc.shift = pps_shift; - txc.stabil = pps_stabil; - txc.jitcnt = pps_jitcnt; - txc.calcnt = pps_calcnt; - txc.errcnt = pps_errcnt; - txc.stbcnt = pps_stbcnt; + txc->offset = save_adjust; + txc->freq = time_freq; + txc->maxerror = time_maxerror; + txc->esterror = time_esterror; + txc->status = time_status; + txc->constant = time_constant; + txc->precision = time_precision; + txc->tolerance = time_tolerance; + txc->time = xtime; + txc->tick = tick; + txc->ppsfreq = pps_freq; + txc->jitter = pps_jitter; + txc->shift = pps_shift; + txc->stabil = pps_stabil; + txc->jitcnt = pps_jitcnt; + txc->calcnt = pps_calcnt; + txc->errcnt = pps_errcnt; + txc->stbcnt = pps_stbcnt; sti(); + return 0; +} + +asmlinkage int sys_adjtimex(struct timex *txc_p) +{ + struct timex txc; /* Local copy of parameter */ + int ret; + + /* Copy the user data space into the kernel copy + * structure. But bear in mind that the structures + * may change + */ + if(copy_from_user(&txc, txc_p, sizeof(struct timex))) + return -EFAULT; + if ((ret = do_adjtimex(&txc))) + return ret; return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state; } diff -u --recursive --new-file v2.1.86/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.1.86/linux/net/bridge/br.c Thu Jan 15 14:33:06 1998 +++ linux/net/bridge/br.c Wed Feb 11 16:16:43 1998 @@ -1386,7 +1386,7 @@ static int br_drop(struct sk_buff *skb) { - kfree_skb(skb, 0); + kfree_skb(skb); return(1); } @@ -1396,7 +1396,7 @@ static int br_dev_drop(struct sk_buff *skb) { - dev_kfree_skb(skb, 0); + dev_kfree_skb(skb); return(1); } diff -u --recursive --new-file v2.1.86/linux/net/core/neighbour.c linux/net/core/neighbour.c --- v2.1.86/linux/net/core/neighbour.c Thu Feb 12 20:56:14 1998 +++ linux/net/core/neighbour.c Wed Feb 11 16:16:43 1998 @@ -1127,7 +1127,7 @@ return; if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); return; } nlh = (struct nlmsghdr*)skb->data; @@ -1147,7 +1147,7 @@ return; if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); return; } nlh = (struct nlmsghdr*)skb->data; diff -u --recursive --new-file v2.1.86/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.1.86/linux/net/ipv4/devinet.c Mon Jan 12 15:28:27 1998 +++ linux/net/ipv4/devinet.c Wed Feb 11 16:16:43 1998 @@ -784,7 +784,7 @@ return; } if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL); return; } diff -u --recursive --new-file v2.1.86/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c --- v2.1.86/linux/net/ipv4/fib_hash.c Sun Nov 30 14:00:39 1997 +++ linux/net/ipv4/fib_hash.c Wed Feb 11 16:16:43 1998 @@ -715,7 +715,7 @@ if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id, f->fn_type, f->fn_scope, &f->fn_key, z, f->fn_tos, FIB_INFO(f)) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); return; } NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE; diff -u --recursive --new-file v2.1.86/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.86/linux/net/ipv6/addrconf.c Mon Jan 12 15:28:28 1998 +++ linux/net/ipv6/addrconf.c Wed Feb 11 16:16:43 1998 @@ -1530,7 +1530,7 @@ return; } if (inet6_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, EINVAL); return; } diff -u --recursive --new-file v2.1.86/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.1.86/linux/net/ipv6/route.c Thu Feb 12 20:56:15 1998 +++ linux/net/ipv6/route.c Wed Feb 11 16:16:43 1998 @@ -1749,7 +1749,7 @@ return; } if (rt6_fill_node(skb, rt, event, 0, 0) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); return; } diff -u --recursive --new-file v2.1.86/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c --- v2.1.86/linux/net/netlink/af_netlink.c Mon Jan 12 15:28:28 1998 +++ linux/net/netlink/af_netlink.c Wed Feb 11 16:16:43 1998 @@ -370,7 +370,7 @@ if (nonblock) { sti(); netlink_unlock(sk); - kfree_skb(skb, 0); + kfree_skb(skb); return -EAGAIN; } interruptible_sleep_on(sk->sleep); @@ -378,7 +378,7 @@ sti(); if (signal_pending(current)) { - kfree_skb(skb, 0); + kfree_skb(skb); return -ERESTARTSYS; } goto retry; @@ -392,7 +392,7 @@ netlink_unlock(sk); return len; } - kfree_skb(skb, 0); + kfree_skb(skb); return -ECONNREFUSED; } @@ -466,8 +466,8 @@ netlink_unlock_table(protocol, allocation == GFP_KERNEL); if (skb2) - kfree_skb(skb2, 0); - kfree_skb(skb, 0); + kfree_skb(skb2); + kfree_skb(skb); } void netlink_set_err(struct sock *ssk, pid_t pid, unsigned group, int code) @@ -630,7 +630,7 @@ static void netlink_destroy_callback(struct netlink_callback *cb) { if (cb->skb) - kfree_skb(cb->skb, 0); + kfree_skb(cb->skb); kfree(cb); } diff -u --recursive --new-file v2.1.86/linux/scripts/Configure linux/scripts/Configure --- v2.1.86/linux/scripts/Configure Mon Jun 16 16:36:02 1997 +++ linux/scripts/Configure Thu Feb 12 16:20:10 1998 @@ -12,10 +12,10 @@ # # ***** IMPORTANT COMPATIBILITY NOTE **** # If configuration changes are made which might adversely effect -# Menuconfig or xconfig, please notify the respective authors so that +# Menuconfig or xconfig, please notify the respective maintainers so that # those utilities can be updated in parallel. # -# Menuconfig: +# Menuconfig: # xconfig: # **************************************** # diff -u --recursive --new-file v2.1.86/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.1.86/linux/scripts/Menuconfig Fri Jan 23 18:10:32 1998 +++ linux/scripts/Menuconfig Thu Feb 12 16:20:10 1998 @@ -19,7 +19,8 @@ # Portions of this script were borrowed from the original Configure # script. # -# Please send comments / questions / bug fixes to roadcapw@cfw.com +# William Roadcap was the original author of Menuconfig. +# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer. # # 070497 Bernhard Kaindl (bkaindl@netway.at) - get default values for # new bool, tristate and dep_tristate parameters from the defconfig file. @@ -726,9 +727,8 @@ Menuconfig has encountered a possible error in one of the kernel's configuration files and is unable to continue. -Please report this to the author . You may also -send a problem report to linux-kernel@vger.rutgers.edu or post a -message to the linux.dev.kernel news group. +Please report this to the maintainer . You may also +send a problem report to . Please indicate the kernel version you are trying to configure and which menu you were trying to enter when this error occurred. @@ -788,8 +788,8 @@ "make clean all" command. If you have verified that your ncurses install is correct, you may email -the author or post a message on the linux.dev.kernel -news group for additional assistance. +the maintainer or post a message to + for additional assistance. EOM cleanup diff -u --recursive --new-file v2.1.86/linux/scripts/README.Menuconfig linux/scripts/README.Menuconfig --- v2.1.86/linux/scripts/README.Menuconfig Thu Apr 18 04:38:54 1996 +++ linux/scripts/README.Menuconfig Thu Feb 12 16:20:10 1998 @@ -188,7 +188,7 @@ intact. Please DO NOT contact Savio with questions about lxdialog. He will not be able to assist. -Please feel free to send any questions, comments or suggestions to -William Roadcap . +William Roadcap was the original author of Menuconfig. +Michael Elizabeth Chastain is the current maintainer.