diff -ur --new-file old/linux/CREDITS new/linux/CREDITS --- old/linux/CREDITS Tue May 11 18:57:14 1999 +++ new/linux/CREDITS Sun May 16 19:26:44 1999 @@ -91,6 +91,11 @@ S: Cambridge, Massachusetts 02139 S: USA +N: Michel Aubry +E: giovanni +D: Aladdin 1533/1543(C) chipset IDE +D: VIA MVP-3/TX Pro III chipset IDE + N: Jens Axboe E: axboe@image.dk D: Linux CD-ROM maintainer @@ -656,7 +661,7 @@ E: rgooch@atnf.csiro.au D: parent process death signal to children D: prctl() syscall -D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's +D: /proc/mtrr support to manipulate MTRRs on Intel P6 family S: CSIRO Australia Telescope National Facility S: P.O. Box 76, Epping S: New South Wales, 2121 @@ -754,6 +759,13 @@ S: London SE16 1GD S: United Kingdom +N: Bart Hartgers +E: bart@etpmod.phys.tue.nl +D: MTRR emulation with Centaur MCRs +S: Gen Stedmanstraat 212 +S: 5623 HZ Eindhoven +S: The Netherlands + N: Kai Harrekilde-Petersen E: khp@dolphinics.no D: Original author of the ftape-HOWTO, i82078 fdc detection code. @@ -765,6 +777,17 @@ E: ajh@primag.co.uk D: Selection mechanism +N: Andre Hedrick +E: hedrick@astro.dyer.vanderbilt.edu +D: Uniform Multi-Platform E-IDE driver +D: Aladdin 1533/1543(C) chipset IDE +D: HighPoint HPT343/5 chipset IDE +D: PIIX chipset IDE +D: Promise Ultra/33 chipset IDE +D: Promise Ultra/66 chipset IDE +S: Nashville, TN +S: USA + N: Jochen Hein E: jochen.hein@delphi.central.de P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B CB 0A DA DA 40 77 05 6C @@ -928,6 +951,10 @@ S: 160 00 Praha 6 S: Czech Republic +N: Andreas S. Krebs +E: akrebs@altavista.net +D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards + N: Niels Kristian Bech Jensen E: nkbj@image.dk W: http://www.image.dk/~nkbj @@ -938,6 +965,13 @@ S: DK-8230 Åbyhøj S: Denmark +N: Andrzej Krzysztofowicz +E: ankry@green.mif.pg.gda.pl +D: Aladdin 1533/1543(C) chipset IDE +D: PIIX chipset IDE +S: Faculty of Applied Phys. & Math. +S: Technical University of Gdansk + N: Michael K. Johnson E: johnsonm@redhat.com W: http://www.redhat.com/~johnsonm @@ -1500,6 +1534,15 @@ E: orc@pell.chi.il.us D: improved memory detection code. +N: Mikulas Patocka +E: mikulas@artax.karlin.mff.cuni.cz +W: http://artax.karlin.mff.cuni.cz/~mikulas/ +P: 1024/BB11D2D5 A0 F1 28 4A C4 14 1E CF 92 58 7A 8F 69 BC A4 D3 +D: Read/write HPFS filesystem +S: Weissova 8 +S: 644 00 Brno +S: Czech Republic + N: Vojtech Pavlik E: vojtech@ucw.cz D: Joystick driver @@ -1729,6 +1772,10 @@ D: added PCI support to the serial driver S: Buckenhof, Germany +N: Michael Schmitz +E: +D: Macintosh IDE Driver + N: Martin Schulze E: joey@linux.de W: http://home.pages.de/~joey/ @@ -1801,7 +1848,7 @@ N: Chris Smith E: csmith@convex.com -D: HPFS filesystem +D: Read only HPFS filesystem S: Richardson, Texas S: USA @@ -2015,6 +2062,9 @@ D: Frame buffer device and XF68_FBDev maintainer D: m68k IDE maintainer D: Amiga Zorro maintainer +D: Amiga Buddha and Catweasel chipset IDE +D: Atari Falcon chipset IDE +D: Amiga Gayle chipset IDE S: C. Huysmansstraat 12 S: B-3128 Baal S: Belgium diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Thu Jun 3 04:26:57 1999 +++ new/linux/Documentation/Configure.help Thu Jun 3 04:28:25 1999 @@ -289,9 +289,9 @@ Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support CONFIG_BLK_DEV_IDE If you say Y here, you will use the full-featured IDE driver to - control up to four IDE interfaces, each being able to serve a - "master" and a "slave" device, for a total of up to eight IDE - disk/cdrom/tape/floppy drives. People with SCSI-only systems + control up to eight IDE interfaces, each being able to serve a + "master" and a "slave" device, for a total of up to sixteen (16) + IDE disk/cdrom/tape/floppy drives. People with SCSI-only systems can say N here. Useful information about large (>540 MB) IDE disks, multiple @@ -370,6 +370,15 @@ root filesystem (the one containing the directory /) is located on the IDE disk. If unsure, say Y. +Use multi-mode by default +CONFIG_IDEDISK_MULTI_MODE + If you get this error, try to enable this option. + + hda: set_multmode: status=0x51 { DriveReady SeekComplete Error } + hda: set_multmode: error=0x04 { DriveStatusError } + + If in doubt, say N. + Include IDE/ATAPI CDROM support CONFIG_BLK_DEV_IDECD If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is @@ -396,6 +405,17 @@ say M here and read Documentation/modules.txt. The module will be called ide-cd.o. +Include CD-Changer Reporting +CONFIG_IDECD_SLOTS + If you have an IDE/ATAPI multi-slot cd-changer and you want + to report which slots have disk-present, say Y. If you say Y + and there is not a multi-slot cdrom present, this code is skipped. + + This could be the bases of multi-disk access based on multi-mounts. + This is still pie-in-the-sky. + + If unsure, say N. + Include IDE/ATAPI TAPE support CONFIG_BLK_DEV_IDETAPE If you have an IDE tape drive using the ATAPI protocol, say Y. @@ -638,14 +658,28 @@ Please read the comments at the top of drivers/block/ns87415.c. +CY82C693 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_CY82C693 + + This driver adds detection and support for the CY82C693 chipset + used on Digital's PC-Alpha 164SX boards. + + This requires CONFIG_IDEDMA_AUTO to be enabled. + + Please read the comments at the top of drivers/block/cy82c693.c + VIA82C586 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_VIA82C586 - This adds initial timing settings for VIA (U)DMA onboard ide - controllers that are ATA3 compliant. May work with ATA4 systems, but - not tested to date. + This allows you to to configure your chipset for a better use while + running (U)DMA: it will allow you to enable efficiently the second + channel dma usage, as it is may not be set by BIOS. It allows you to + run a kernel command line at boot time in order to set fifo config. + If no command line is provided, it will try to set fifo configuration + at its best. It will allow you to get a proc/ide/via display + (while running a "cat") provided you enabled "proc" support and + set DISPLAY_APOLLO_TIMINGS in via82c586.c - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. + This requires CONFIG_IDEDMA_AUTO to be enabled. If unsure, say N. @@ -653,6 +687,81 @@ CONFIG_BLK_DEV_CMD646 Say Y here if you have an IDE controller like this. +ALI M15x3 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_ALI15X3 + This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C + onboard chipsets. It also tests for Simplex mode and enables + normal dual channel support. + + This requires CONFIG_IDEDMA_AUTO to be enabled. + + Please read the comments at the top of drivers/block/alim15x3.c + + If unsure, say N. + +PROMISE PDC20246 support (EXPERIMENTAL) +CONFIG_BLK_DEV_PDC20246 + This driver adds up to 4 more eide devices sharing a single interrupt. + This add-on card is a bootable PCI UDMA controller. + Since multiple cards can be installed and there are BIOS ROM problems + that happen if the BIOS revisions of all installed cards (three-max) + do not match. Should you be unable to make new BIOS chips with a burner, + the driver attempts to dynamic tuning of the chipset at boot-time + for max-speed. Ultra33 BIOS 1.25 or new required for more than one card. + + This requires CONFIG_IDEDMA_AUTO to be enabled. + + Please read the comments at the top of drivers/block/pdc202xx.c + + If unsure, say N. + +PROMISE PDC20262 support (EXPERIMENTAL) +CONFIG_BLK_DEV_PDC20262 + This driver adds up to 4 more eide devices sharing a single interrupt. + This add-on card is a bootable PCI UDMA ATA-66 controller. + The driver attempts to dynamic tuning of the chipset at boot-time + for max-speed. Note tested limits are UDMA-2. + Ultra66 BIOS 1.11 or newer required. + + This requires CONFIG_IDEDMA_AUTO to be enabled. + + Please read the comments at the top of drivers/block/pdc202xx.c + + If unsure, say N. + +AEC6210 chipset support +CONFIG_BLK_DEV_AEC6210 + This driver adds up to 4 more eide devices sharing a single interrupt. + This add-on card is a bootable PCI UDMA controller. In order to get this + card to initialize correctly in some cases, you should include this driver. + + This prefers CONFIG_IDEDMA_AUTO to be enabled, regardless. + + Please read the comments at the top of drivers/block/aec6210.c + +Intel PIIXn chipsets support (EXPERIMENTAL) +CONFIG_BLK_DEV_PIIX + This driver adds PIO mode setting and tuning for all PIIX IDE + controllers by Intel. Since the BIOS can sometimes improperly tune + PIO 0-4 mode settings, this allows dynamic tuning of the chipset + via the standard end-user tool 'hdparm'. + + Please read the comments at the top of drivers/block/piix.c + + If unsure, say N. + +HPT343 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_HPT343 + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT343 chipset in its current form is a non-bootable + PCI UDMA controller. This driver requires dynamic tuning of the + chipset during the ide-probe at boot. It is reported to support DVD + II drives, by the manufacturer. + + This requires CONFIG_IDEDMA_AUTO to be enabled. + + Please read the comments at the top of drivers/block/hpt343.c + QDI QD6580 support CONFIG_BLK_DEV_QD6580 This driver is enabled at runtime using the "ide0=qd6580" kernel @@ -676,6 +785,68 @@ I/O speeds to be set as well. See the files Documentation/ide.txt and drivers/block/ali14xx.c for more info. +Amiga builtin Gayle IDE interface support +CONFIG_BLK_DEV_GAYLE + This is the IDE driver for the builtin IDE interface on some Amiga + models. It supports both the `A1200 style' (used in A600 and A1200) + and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE interface. + Say Y if you have such an Amiga model and want to use IDE devices + (hard disks, CD-ROM drives, etc.) that are connected to the builtin + IDE interface. + +Falcon IDE interface support +CONFIG_BLK_DEV_FALCON_IDE + This is the IDE driver for the builtin IDE interface on the Atari Falcon. + Say Y if you have a Falcon and want to use IDE devices (hard disks, + CD-ROM drives, etc.) that are connected to the builtin IDE interface. + +Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL) +CONFIG_BLK_DEV_BUDDHA + This is the IDE driver for the IDE interfaces on the Buddha and + Catweasel expansion boards. It supports up to two interfaces on the + Buddha and three on the Catweasel. + Say Y if you have a Buddha or Catweasel expansion board and want to + use IDE devices (hard disks, CD-ROM drives, etc.) that are connected + to one of its IDE interfaces. + +Amiga IDE Doubler support (EXPERIMENTAL) +CONFIG_BLK_DEV_IDEDOUBLER + This driver provides support for the so called `IDE doublers' (made by + various manufacturers, e.g. Eyetech) that can be connected to the + builtin IDE interface of some Amiga models. Using such an IDE doubler, + you can connect up to four instead of two IDE devices on the Amiga's + builtin IDE interface. + Note that the normal Amiga Gayle IDE driver may not work correctly if + you have an IDE doubler and don't enable this driver! + Say Y if you have an IDE doubler. The driver is enabled at kernel + runtime using the "ide=doubler" kernel boot parameter. + + Support for PowerMac IDE devices (must also enable IDE) + CONFIG_BLK_DEV_IDE_PMAC + No help for CONFIG_BLK_DEV_IDE_PMAC + + PowerMac IDE DMA support + CONFIG_BLK_DEV_IDEDMA_PMAC + No help for CONFIG_BLK_DEV_IDEDMA_PMAC + + Use DMA by default + CONFIG_PMAC_IDEDMA_AUTO + No help for CONFIG_PMAC_IDEDMA_AUTO + +Macintosh Quadra/Powerbook IDE interface support +CONFIG_BLK_DEV_MAC_IDE + This is the IDE driver for the builtin IDE interface on the some m68k + Macintosh models. It supports both the `Quadra style' (used in Quadra/ + Centris 630 and Performa 588 models) and `Powerbook style' (used in the + Powerbook 150 and 190 models) IDE interface. + Say Y if you have such an Macintosh model and want to use IDE devices + (hard disks, CD-ROM drives, etc.) that are connected to the builtin + IDE interface. + + RapIDE interface support + CONFIG_BLK_DEV_IDE_RAPIDE + No help for CONFIG_BLK_DEV_IDE_RAPIDE + XT hard disk support CONFIG_BLK_DEV_XD Very old 8 bit hard disk controllers used in the IBM XT computer @@ -7362,14 +7533,24 @@ directories that are mount points on the local filesystem (this is how nfsd behaves on Sun systems), say yes here. If unsure, say N. -OS/2 HPFS filesystem support (read only) +OS/2 HPFS filesystem support (read/write) CONFIG_HPFS_FS OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS is the filesystem used for organizing files on OS/2 hard disk - partitions. Say Y if you want to be able to read files from an OS/2 - HPFS partition of your hard drive. OS/2 floppies however are in - regular MSDOS format, so you don't need this option in order to be - able to read them. Read Documentation/filesystems/hpfs.txt. + partitions. Say Y if you want to be able to read and write files + on an OS/2 HPFS partition of your hard drive. OS/2 floppies however + are in regular MSDOS format, so you don't need this option in order + to be able to read them. Read Documentation/filesystems/hpfs.txt. + + Write support is new and experimental. I don't think it's so + "experimental" that it corrupts disks. (but you know: "There's no + warranty") There are many checks and filesystem is remounted read-only + if any inconsistency found. I use it quite long time and it works. + + This driver may not be able to write to HPFS386 disks on Warp server. + HPFS386 on Warp client seems to work ok. If some unknown HPFS386 + structures are deteced, they are not destroyed and filesystem is + remounted read-only. This filesystem is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8895,6 +9076,9 @@ The AMD K6-2 (stepping 8 and above) and K6-3 processors have two MTRRs. These are supported. + + The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These + are supported. Saying Y here also fixes a problem with buggy SMP BIOSes which only set the MTRRs for the boot CPU and not the secondary CPUs. This can diff -ur --new-file old/linux/Documentation/devices.tex new/linux/Documentation/devices.tex --- old/linux/Documentation/devices.tex Sun Aug 16 20:35:51 1998 +++ new/linux/Documentation/devices.tex Thu May 13 20:00:08 1999 @@ -254,7 +254,9 @@ \major{86}{}{char }{SCSI media changer} \major{87}{}{char }{Sony Control-A1 stereo control bus} \major{88}{}{char }{COMX synchronous serial card} +\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface} \major{89}{}{char }{I$^2$C bus interface} +\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} \major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)} \major{91}{}{char }{CAN-Bus controller} \major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card} @@ -1746,11 +1748,31 @@ \end{devicelist} \begin{devicelist} +\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface} + \minor{0}{/dev/hdm}{Master: whole disk (or CD-ROM)} + \minor{64}{/dev/hdn}{Slave: whole disk (or CD-ROM)} +\end{devicelist} + +\noindent +Partitions are handled the same way as for the first interface (see +major number 3). + +\begin{devicelist} \major{89}{}{char }{I$^2$C bus interface} \minor{0}{/dev/i2c0}{First I$^2$C adapter} \minor{1}{/dev/i2c1}{Second I$^2$C adapter} \minordots \end{devicelist} + +\begin{devicelist} +\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} + \minor{0}{/dev/hdo}{Master: whole disk (or CD-ROM)} + \minor{64}{/dev/hdp}{Slave: whole disk (or CD-ROM)} +\end{devicelist} + +\noindent +Partitions are handled the same way as for the first interface (see +major number 3). \begin{devicelist} \major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)} diff -ur --new-file old/linux/Documentation/devices.txt new/linux/Documentation/devices.txt --- old/linux/Documentation/devices.txt Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/devices.txt Thu May 13 20:00:08 1999 @@ -1215,10 +1215,24 @@ 1 = /dev/comx1 COMX channel 1 ... + block Sixth IDE hard disk/CD-ROM interface + 0 = /dev/hdm Master: whole disk (or CD-ROM) + 64 = /dev/hdn Slave: whole disk (or CD-ROM) + + Partitions are handled the same way as for the first + interface (see major number 3). + 89 char I2C bus interface 0 = /dev/i2c0 First I2C adapter 1 = /dev/i2c1 Second I2C adapter ... + + block Seventh IDE hard disk/CD-ROM interface + 0 = /dev/hdo Master: whole disk (or CD-ROM) + 64 = /dev/hdp Slave: whole disk (or CD-ROM) + + Partitions are handled the same way as for the first + interface (see major number 3). 90 char Memory Technology Device (RAM, ROM, Flash) 0 = /dev/mtd0 First MTD (rw) diff -ur --new-file old/linux/Documentation/filesystems/hpfs.txt new/linux/Documentation/filesystems/hpfs.txt --- old/linux/Documentation/filesystems/hpfs.txt Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/filesystems/hpfs.txt Sun May 16 19:26:44 1999 @@ -1,27 +1,272 @@ -Linux can read, but not write, OS/2 HPFS partitions. +Read/Write HPFS 1.99b +1998-1999, Mikulas Patocka -Mount options are the same as for msdos partitions. +email: mikulas@artax.karlin.mff.cuni.cz +homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi - uid=nnn All files in the partition will be owned by user id nnn. - gid=nnn All files in the partition will be in group nnn. - umask=nnn The permission mask (see umask(1)) for the partition. - conv=binary Data is returned exactly as is, with CRLFs. [default] - conv=text (Carriage return, line feed) is replaced with newline. - conv=auto Chooses, file by file, conv=binary or conv=text (by guessing) +CREDITS: +Chris Smith, 1993, original read-only HPFS, some code and hpfs structures file + is taken from it +Jacques Gelinas, MSDos mmap, Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993) +Werner Almesberger, 1992, 1993, MSDos option parser & CR/LF conversion -There are mount options unique to HPFS. +Mount options - case=lower Convert file names to lower case. [default] - case=asis Return file names as is, in mixed case. +uid=xxx,gid=xxx,umask=xxx (default uid=gid=0 umask=default_system_umask) + Set owner/group/mode for files that do not have it specified in extended + attributes. Mode is inverted umask - for example umask 027 gives owner + all permission, group read permission and anybody else no access. Note + that for files mode is anded with 0666. If you want files to have 'x' + rights, you must use extended attributes. +case=lower,asis (default asis) + File name lowercasing in readdir. +conv=binary,text,auto (default binary) + CR/LF -> LF conversion, if auto, decision is made according to extension + - there is a list of text extensions (I thing it's better to not convert + text file than to damage binary file). If you want to change that list, + change it in the source. Original readonly HPFS contained some strange + heuristic alghoritm that I removed. I thing it's danger to let the + computer decide whether file is text or binary. For example, DJGPP + binaries contain small text message at the beginning and they could be + misidentified and damaged under some circumstances. +check=none,normal,strict (default normal) + Check level. Selecting none will cause only little speedup and big + danger. I tried to write it so that it won't crash if check=normal on + corrupted filesystems. check=strict means many superflous checks - + used for debugging (for example it checks if file is allocated in + bitmaps when accessing it). +errors=continue,remount-ro,panic (default remount-ro) + Behaviour when filesystem errors found. +chkdsk=no,errors,always (default errors) + When to mark filesystem dirty so that OS/2 checks it. +eas=no,ro,rw (default rw) + What to do with extended attributes. 'no' - ignore them and use always + values specified in uid/gid/mode options. 'ro' - read extended + attributes but do not create them. 'rw' - create extended attributes + when you use chmod/chown/chgrp/mknod/ln -s on the filesystem. +timeshift=(-)nnn (default 0) + Shifts the time by nnn seconds. For example, if you see under linux + one hour more, than under os/2, use timeshift=-3600. - nocheck Proceed even if "Improperly stopped flag is set" -Case is not significant in filename matching, like real HPFS. +File names +As in OS/2, filenames are case insensitive. However, shell thinks that names +are case sensitive, so for example when you create a file FOO, you can use +'cat FOO', 'cat Foo', 'cat foo' or 'cat F*' but not 'cat f*'. Note, that you +also won't be able to compile linux kernel (and maybe other things) on HPFS +because kernel creates different files with names like bootsect.S and +bootsect.s. When searching for file thats name has characters >= 128, codepages +are used - see below. +OS/2 ignores dots and spaces at the end of file name, so this driver does as +well. If you create 'a. ...', the file 'a' will be created, but you can still +access it under names 'a.', 'a..', 'a . . . ' etc. -Command line example - mkdir -p /os2/c - mount -t hpfs -o uid=100,gid=100 /dev/sda6 /os2/c -/etc/fstab example - /dev/sdb5 /d/f hpfs ro,uid=402,gid=402,umask=002 +Extended attributes + +On HPFS partion, OS/2 can associate to each file a special information called +extended attributes. Extended attributes are pairs of (key,value) where key is +an ascii string identifying that attribute and value is any string of bytes of +variable length. OS/2 stores window and icon positions and file types there. So +why not use it for unix-specific info like file owner or access rights? This +driver can do it. If you chown/chgrp/chmod on a hpfs partion, extended +attributes with keys "UID", "GID" or "MODE" and 2-byte values are created. Only +that extended attributes those value differs from defaults specified in mount +options are created. Once created, the extended attributes are never deleted, +they're just changed. It means that when your default uid=0 and you type +something like 'chown luser file; chown root file' the file will contain +extended attribute UID=0. And when you umount the fs and mount it again with +uid=luser_uid, the file will be still owned by root! If you chmod file to 444, +extended attribute "MODE" will not be set, this special case is done by setting +read-only flag. When you mknod a block or char device, besides "MODE", the +special 4-byte extended attribute "DEV" will be created containing the device +number. Currently this driver cannot resize extended attributes - it means +that if somebody (I don't know who?) has set "UID", "GID", "MODE" or "DEV" +attributes with different sizes, they won't be rewritten and changing these +values doesn't work. + + +Symlinks + +You can do symlinks on HPFS partion, symlinks are achieved by setting extended +attribute named "SYMLINK" with symlink value. Like on ext2, you can chown and +chgrp symlinks but I don't know what is it good for. chmoding symlink results +in chmoding file where symlink points. These symlinks are just for Linux use and +incompatible with OS/2. OS/2 PmShell symlinks are not supported because they are +stored in very crazy way. They tried to do it so that link changes when file is +moved ... sometimes it works. But the link is partly stored in directory +extended attributes and partly in OS2SYS.INI. I don't want (and don't know how) +to analyze or change OS2SYS.INI. + + +Codepages + +HPFS can contain several uppercasing tables for several codepages and each +file has a pointer to codepage it's name is in. However OS/2 was created in +America where people don't care much about codepages and so multiple codepages +support is quite buggy. I have Czech OS/2 working in codepage 852 on my disk. +Once I booted English OS/2 working in cp 850 and I created a file on my 852 +partion. It marked file name codepage as 850 - good. But when I again booted +Czech OS/2, the file was completely inaccessible under any name. It seems that +OS/2 uppercases the search pattern with it's system code page (852) and file +name it's comparing to with its code page (850). These could never match. Is it +really what IBM developers wanted? But problems countinue. When I created in +Czech OS/2 another file in that direcotry, that file was inaccesible too. OS/2 +probably uses different uppercasing method when searching where to place a file +(note, that files in HPFS directory must be sorted) and when searching for +a file. Finally when I opened this directory in PmShell, PmShell crashed (the +funny thing was that, when rebooted, PmShell tried to reopen this directory +again :-). chkdsk happily ignores these errors and only low-level disk +modification saved me. Never mix different language versions of OS/2 on one +system although HPFS was designed to allow that. +OK, I could implement complex codepage support to this driver but I think it +would cause more problems than benefit with such buggy implementation in OS/2. +So this driver simply uses first codepage it finds for uppercasing and +lowercasing no matter what's file codepage index. Usually all file names are in +this codepage - if you don't try to do what I described above :-) + + +Known bugs + +HPFS386 on OS/2 server is not supported. HPFS386 installed on normal OS/2 client +should work. If you have OS/2 server, use only read-only mode. I don't know how +to handle some HPFS386 structures like access control list or extended perm +list, I don't know how to delete them when file is deleted and how to not +overwrite them with extended attributes. Send me some info on these structures +and I'll make it. However, this driver should detect presence of HPFS386 +structures, remount read-only and not destroy them (I hope). + +When there's not enough space for extended attributes, they will be truncated +and no error is returned. + +OS/2 can't access files if the path is longer than about 256 chars but this +driver allows you to do it. chkdsk ignores such errors. + +Sometimes you won't be able to delete some files on a very full filesystem +(returning error ENOSPC). That's because file in non-leaf node in directory tree +(one directory, if it's large, has dirents in tree on HPFS) must be replaced +with another node when deleted. And that new file might have larger name than +the old one so the new name doesn't fit in directory node (dnode). And that +would result in directory tree splitting, that takes disk space. Workaround is +to delete other files that are leaf (probability that the file is non-leaf is +about 1/50) or to truncate file first to make some space. +You encounter this problem only if you have many directories so that +preallocated directory band is full i.e. + number_of_directories / size_of_filesystem_in_mb > 4. + +You can't delete open directories. + +You can't rename over directories (what is it good for?). + +Renaming files so that only case changes doesn't work. This driver supports it +but vfs doesn't. Something like 'mv file FILE' won't work. + +All atimes and directory mtimes are not updated. That's because of performance +reasons. If you extremely wish to update them, let me know, I'll write it (but +it will be slow). + +When the system is out of memory and swap, it may slightly corrupt filesystem +(lost files, unbalanced directories). (I guess all filesystem may do it). + +When compiled, you get warning: function declaration isn't a prototype. Does +anybody know what does it mean? + + +What does "unbalanced tree" message mean? + +Old versions of this driver created sometimes unbalanced dnode trees. OS/2 +chkdsk doesn't scream if the tree is unbalanced (and sometimes creates +unbalanced trees too :-) but both HPFS and HPFS386 contain bug that it rarely +crashes when the tree is not balanced. This driver handles unbalanced trees +correctly and writes warning if it finds them. If you see this message, this is +probably because of directories created with old version of this driver. +Workaround is to move all files from that directory to another and then back +again. Do it in Linux, not OS/2! If you see this message in directory that is +whole created by this driver, it is BUG - let me know about it. + + +Bugs in OS/2 + +When you have two (or more) lost directories pointing each to other, chkdsk +locks up when repairing filesystem. + +Sometimes (I think it's random) when you create a file with one-char name under +OS/2, OS/2 marks it as 'long'. chkdsk then removes this flag saying "Minor fs +error corrected". + +File names like "a .b" are marked as 'long' by OS/2 but chkdsk "corrects" it and +marks them as short (and writes "minor fs error corrected"). This bug is not in +HPFS386. + +Codepage bugs decsribed above. + +If you don't install fixpacks, there are many, many more... + + +History + +0.90 First public release +0.91 Fixed bug that caused shooting to memory when write_inode was called on + open inode (rarely happened) +0.92 Fixed a little memory leak in freeing directory inodes +0.93 Fixed bug that locked up the machine when there were too many filenames + with first 15 characters same + Fixed write_file to zero file when writing behind file end +0.94 Fixed a little memory leak when trying to delete busy file or directory +0.95 Fixed a bug that i_hpfs_parent_dir was not updated when moving files +1.90 First version for 2.1.1xx kernels +1.91 Fixed a bug that chk_sectors failed when sectors were at the end of disk + Fixed a race-condition when write_inode is called while deleting file + Fixed a bug that could possibly happen (with very low probability) when + using 0xff in filenames + Rewritten locking to avoid race-conditions + Mount option 'eas' now works + Fsync no longer returns error + Files beginning with '.' are marked hidden + Remount support added + Alloc is not so slow when filesystem becomes full + Atimes are no more updated because it slows down operation + Code cleanup (removed all commented debug prints) +1.92 Corrected a bug when sync was called just before closing file +1.93 Modified, so that it works with kernels >= 2.1.131, I don't know if it + works with previous versions + Fixed a possible problem with disks > 64G (but I don't have one, so I can't + test it) + Fixed a file overflow at 2G + Added new option 'timeshift' + Changed behaviour on HPFS386: It is now possible to operate on HPFS386 in + read-only mode + Fixed a bug that slowed down alloc and prevented allocating 100% space + (this bug was not destructive) +1.94 Added workaround for one bug in Linux + Fixed one buffer leak + Fixed some incompatibilities with large extended attributes (but it's still + not 100% ok, I have no info on it and OS/2 doesn't want to create them) + Rewritten allocation + Fixed a bug with i_blocks (du sometimes didn't display correct values) + Directories have no longer archive attribute set (some programs don't like + it) + Fixed a bug that it set badly one flag in large anode tree (it was not + destructive) +1.95 Fixed one buffer leak, that could happen on corrupted filesystem + Fixed one bug in allocation in 1.94 +1.96 Added workaround for one bug in OS/2 (HPFS locked up, HPFS386 reported + error sometimes when opening directories in PMSHELL) + Fixed a possible bitmap race + Fixed possible problem on large disks + You can now delete open files + Fixed a nondestructive race in rename +1.97 Support for HPFS v3 (on large partitions) + Fixed a bug that it didn't allow creation of files > 128M (it should be 2G) +1.97.1 Changed names of global symbols + Fixed a bug when chmoding or chowning root directory +1.98 Fixed a deadlock when using old_readdir + Better directory handling; workaround for "unbalanced tree" bug in OS/2 +1.99 Corrected a possible problem when there's not enough space while deleting + file + Now it tries to truncate the file if there's not enough space when deleting + Removed a lot of redundat code + + + vim: set textwidth=80: diff -ur --new-file old/linux/Documentation/mtrr.txt new/linux/Documentation/mtrr.txt --- old/linux/Documentation/mtrr.txt Mon May 10 19:32:45 1999 +++ new/linux/Documentation/mtrr.txt Sun May 16 19:13:20 1999 @@ -1,5 +1,5 @@ MTRR (Memory Type Range Register) control -2 May 1998 +16 May 1999 Richard Gooch @@ -31,8 +31,10 @@ reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1 reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 =============================================================================== -Creating MTRRs from the shell: +Creating MTRRs from the C-shell: # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr +or if you use bash: +# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr And the result thereof: % cat /proc/mtrr @@ -79,8 +81,10 @@ NOTE: You can only create type=uncachable region, if the first region that you created is type=write-combining. =============================================================================== -Removing MTRRs from the shell: +Removing MTRRs from the C-shell: % echo "disable=2" >! /proc/mtrr +or using bash: +% echo "disable=2" >| /proc/mtrr =============================================================================== Reading MTRRs from a C programme using ioctl()'s: diff -ur --new-file old/linux/Documentation/svga.txt new/linux/Documentation/svga.txt --- old/linux/Documentation/svga.txt Sat Jul 11 00:18:29 1998 +++ new/linux/Documentation/svga.txt Fri May 14 21:47:01 1999 @@ -1,5 +1,5 @@ - Video Mode Selection Support 2.11 - (c) 1995--1997 Martin Mares, + Video Mode Selection Support 2.13 + (c) 1995--1999 Martin Mares, -------------------------------------------------------------------------------- 1. Intro @@ -9,6 +9,11 @@ to usage of the BIOS, the selection is limited to boot time (before the kernel decompression starts) and works only on 80X86 machines. + ** Short intro for the impatient: Just use vga=ask for the first time, + ** enter `scan' on the video mode prompt, pick the mode you want to use, + ** remember its mode ID (the four-digit hexadecimal number) and then + ** set the vga parameter to this number (converted to decimal first). + The video mode to be used is selected by a kernel parameter which can be specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..." option of LILO (or some other boot loader you use) or by the "vidmode" utility @@ -268,3 +273,4 @@ - Removed the doc section describing adding of new probing functions as I try to get rid of _all_ hardware probing here. 2.12 (25-May-98)- Added support for VESA frame buffer graphics. +2.13 (14-May-99)- Minor documentation fixes. diff -ur --new-file old/linux/MAINTAINERS new/linux/MAINTAINERS --- old/linux/MAINTAINERS Sat May 8 21:49:46 1999 +++ new/linux/MAINTAINERS Sun May 16 19:26:44 1999 @@ -361,6 +361,12 @@ W: http://www.uni-mainz.de/~langm000/linux.html S: Maintained +HPFS FILESYSTEM +P: Mikulas Patocka +M: mikulas@artax.karlin.mff.cuni.cz +W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi +S: Maintained + IDE DRIVER [GENERAL] P: Andre Hedrick M: hedrick@astro.dyer.vanderbilt.edu diff -ur --new-file old/linux/Makefile new/linux/Makefile --- old/linux/Makefile Thu Jun 3 04:26:57 1999 +++ new/linux/Makefile Thu Jun 3 04:28:24 1999 @@ -1,6 +1,6 @@ VERSION = 2 -PATCHLEVEL = 2 -SUBLEVEL = 9 +PATCHLEVEL = 3 +SUBLEVEL = 2 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -ur --new-file old/linux/README new/linux/README --- old/linux/README Thu Jan 7 17:41:55 1999 +++ new/linux/README Thu May 13 19:56:25 1999 @@ -1,9 +1,23 @@ - Linux kernel release 2.2.xx + Linux kernel release 2.3.xx -These are the release notes for Linux version 2.2. Read them carefully, +These are the release notes for Linux version 2.3. Read them carefully, as they tell you what this is all about, explain how to install the kernel, and what to do if something goes wrong. +Linux version 2.3 is a DEVELOPMENT kernel, and not intended for general +public use. Different releases may have various and sometimes severe +bugs. It is *strongly* recommended that you back up the previous kernel +before installing any new 2.3.xx release. + +If you need to use a proven and stable Linux kernel, please use 1.2.13, +2.0.36 or 2.2.xx. All features which will be in the 2.3.xx releases will +be contained in 2.4.xx when the code base has stabilized again. + +If you decide to use 2.3, it is recommended that you join the kernel mailing +list. To do this, e-mail majordomo@vger.rutgers.edu, and put in the body +of the message "subscribe linux-kernel" or "subscribe linux-kernel-digest" +for a daily digest of the mailing list (it is a high-traffic list.) + However, please make sure you don't ask questions which are already answered in various files in the Documentation directory. See DOCUMENTATION below. @@ -48,12 +62,12 @@ - If you install the full sources, do a cd /usr/src - gzip -cd linux-2.2.XX.tar.gz | tar xfv - + gzip -cd linux-2.3.XX.tar.gz | tar xfv - to get it all put in place. Replace "XX" with the version number of the latest kernel. - - You can also upgrade between 2.2.xx releases by patching. Patches are + - You can also upgrade between 2.3.xx releases by patching. Patches are distributed in the traditional gzip and the new bzip2 format. To install by patching, get all the newer patch files and do @@ -91,7 +105,7 @@ SOFTWARE REQUIREMENTS - Compiling and running the 2.2.x kernels requires up-to-date + Compiling and running the 2.3.x kernels requires up-to-date versions of various software packages. Consult ./Documentation/Changes for the minimum version numbers required and how to get updates for these packages. Beware that using diff -ur --new-file old/linux/arch/alpha/kernel/alpha_ksyms.c new/linux/arch/alpha/kernel/alpha_ksyms.c --- old/linux/arch/alpha/kernel/alpha_ksyms.c Sun Jan 17 02:02:50 1999 +++ new/linux/arch/alpha/kernel/alpha_ksyms.c Fri May 14 21:41:22 1999 @@ -52,6 +52,7 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(perf_irq); diff -ur --new-file old/linux/arch/alpha/kernel/fpreg.c new/linux/arch/alpha/kernel/fpreg.c --- old/linux/arch/alpha/kernel/fpreg.c Sun Aug 9 21:09:05 1998 +++ new/linux/arch/alpha/kernel/fpreg.c Fri May 14 21:41:22 1999 @@ -1,10 +1,10 @@ /* - * kernel/fpreg.c + * arch/alpha/kernel/fpreg.c * * (C) Copyright 1998 Linus Torvalds */ -#ifdef __alpha_cix__ +#if defined(__alpha_cix__) || defined(__alpha_fix__) #define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); #else #define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val)); @@ -52,7 +52,7 @@ return val; } -#ifdef __alpha_cix__ +#if defined(__alpha_cix__) || defined(__alpha_fix__) #define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); #else #define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val)); diff -ur --new-file old/linux/arch/alpha/kernel/head.S new/linux/arch/alpha/kernel/head.S --- old/linux/arch/alpha/kernel/head.S Mon Oct 12 20:40:12 1998 +++ new/linux/arch/alpha/kernel/head.S Fri May 14 21:41:22 1999 @@ -32,24 +32,26 @@ #ifdef __SMP__ .align 3 - .globl __start_cpu - .ent __start_cpu - /* On entry here from SRM console, the HWPCB of this processor - has been loaded, and $27 contains the task pointer */ -__start_cpu: - .prologue 0 - /* First order of business, load the GP */ - br $26,1f -1: ldgp $29,0($26) - /* We need to get current loaded up with our first task... */ - mov $27,$8 - /* Set FEN */ - lda $16,1($31) - call_pal PAL_wrfen - /* ... and then we can start the processor. */ - jsr $26,start_secondary + .globl __smp_callin + .ent __smp_callin + /* On entry here from SRM console, the HWPCB of the per-cpu + slot for this processor has been loaded. We've arranged + for the UNIQUE value for this process to contain the PCBB + of the target idle task. */ +__smp_callin: + .prologue 1 + ldgp $29,0($27) # First order of business, load the GP. + + call_pal PAL_rduniq # Grab the target PCBB. + mov $0,$16 # Install it. + call_pal PAL_swpctx + + lda $8,0x3fff # Find "current". + bic $30,$8,$8 + + jsr $26,smp_callin call_pal PAL_halt - .end __start_cpu + .end __smp_callin #endif /* __SMP__ */ .align 3 diff -ur --new-file old/linux/arch/alpha/kernel/irq.c new/linux/arch/alpha/kernel/irq.c --- old/linux/arch/alpha/kernel/irq.c Sun Jan 17 02:02:50 1999 +++ new/linux/arch/alpha/kernel/irq.c Fri May 14 21:41:22 1999 @@ -192,13 +192,21 @@ } void -disable_irq(unsigned int irq_nr) +disable_irq_nosync(unsigned int irq_nr) { unsigned long flags; save_and_cli(flags); mask_irq(irq_nr); restore_flags(flags); +} + +void +disable_irq(unsigned int irq_nr) +{ + /* This works non-SMP, and SMP until we write code to distribute + interrupts to more that cpu 0. */ + disable_irq_nosync(irq_nr); } void diff -ur --new-file old/linux/arch/alpha/kernel/process.c new/linux/arch/alpha/kernel/process.c --- old/linux/arch/alpha/kernel/process.c Mon May 10 18:55:21 1999 +++ new/linux/arch/alpha/kernel/process.c Fri May 14 21:41:23 1999 @@ -75,33 +75,46 @@ return 0; } -static void __attribute__((noreturn)) -do_cpu_idle(void) +#ifdef __SMP__ +void +cpu_idle(void *unused) { /* An endless idle loop with no priority at all. */ current->priority = 0; + current->counter = -100; + while (1) { - check_pgt_cache(); - run_task_queue(&tq_scheduler); - current->counter = 0; - schedule(); - } -} + /* FIXME -- EV6 and LCA45 know how to power down + the CPU. */ -#ifdef __SMP__ -void -cpu_idle(void *unused) -{ - do_cpu_idle(); + /* Although we are an idle CPU, we do not want to + get into the scheduler unnecessarily. */ + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } + } } #endif asmlinkage int sys_idle(void) { - if (current->pid == 0) - do_cpu_idle(); - return -EPERM; + if (current->pid != 0) + return -EPERM; + + /* An endless idle loop with no priority at all. */ + current->priority = 0; + current->counter = -100; + init_idle(); + + while (1) { + /* FIXME -- EV6 and LCA45 know how to power down + the CPU. */ + + schedule(); + check_pgt_cache(); + } } void diff -ur --new-file old/linux/arch/alpha/kernel/proto.h new/linux/arch/alpha/kernel/proto.h --- old/linux/arch/alpha/kernel/proto.h Mon Feb 22 04:06:36 1999 +++ new/linux/arch/alpha/kernel/proto.h Fri May 14 21:41:23 1999 @@ -151,6 +151,8 @@ extern void setup_smp(void); extern int smp_info(char *buffer); extern void handle_ipi(struct pt_regs *); +extern void smp_percpu_timer_interrupt(struct pt_regs *); +extern int smp_boot_cpuid; /* bios32.c */ extern void reset_for_srm(void); @@ -178,7 +180,7 @@ extern void wrmces(unsigned long mces); extern void cserve_ena(unsigned long); extern void cserve_dis(unsigned long); -extern void __start_cpu(unsigned long); +extern void __smp_callin(void); /* entry.S */ extern void entArith(void); diff -ur --new-file old/linux/arch/alpha/kernel/signal.c new/linux/arch/alpha/kernel/signal.c --- old/linux/arch/alpha/kernel/signal.c Mon Oct 12 20:40:12 1998 +++ new/linux/arch/alpha/kernel/signal.c Fri May 14 21:41:23 1999 @@ -24,6 +24,9 @@ #include #include +#include "proto.h" + + #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) diff -ur --new-file old/linux/arch/alpha/kernel/smp.c new/linux/arch/alpha/kernel/smp.c --- old/linux/arch/alpha/kernel/smp.c Mon May 10 18:55:21 1999 +++ new/linux/arch/alpha/kernel/smp.c Fri May 14 21:41:23 1999 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include #include "proto.h" +#include "irq.h" + #define DEBUG_SMP 0 #if DEBUG_SMP @@ -37,62 +40,44 @@ #define DBGS(args) #endif -struct ipi_msg_flush_tb_struct { - volatile unsigned int flush_tb_mask; - union { - struct mm_struct * flush_mm; - struct vm_area_struct * flush_vma; - } p; - unsigned long flush_addr; - unsigned long flush_end; -}; - -static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned; -static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED; - +/* A collection of per-processor data. */ struct cpuinfo_alpha cpu_data[NR_CPUS]; -spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - -unsigned int boot_cpu_id = 0; -static int smp_activated = 0; +/* A collection of single bit ipi messages. */ +static struct { + unsigned long bits __cacheline_aligned; +} ipi_data[NR_CPUS]; -int smp_found_config = 0; /* Have we found an SMP box */ -static int max_cpus = -1; +enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_STOP, +}; -unsigned int cpu_present_map = 0; +spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; -int smp_num_cpus = 1; -int smp_num_probed = 0; /* Internal processor count */ +/* Set to a secondary's cpuid when it comes online. */ +static unsigned long smp_secondary_alive; -int smp_threads_ready = 0; -volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -volatile unsigned long smp_spinning[NR_CPUS] = { 0, }; +unsigned long cpu_present_mask; /* Which cpus ids came online. */ +static int max_cpus = -1; /* Command-line limitation. */ +int smp_boot_cpuid; /* Which processor we booted from. */ +int smp_num_probed; /* Internal processor count */ +int smp_num_cpus = 1; /* Number that came online. */ +int smp_threads_ready; /* True once the per process idle is forked. */ cycles_t cacheflush_time; -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; - -volatile int ipi_bits[NR_CPUS] __cacheline_aligned; - -unsigned long boot_cpu_palrev; - -volatile int smp_commenced = 0; -volatile int smp_processors_ready = 0; - -volatile int cpu_number_map[NR_CPUS]; -volatile int cpu_logical_map[NR_CPUS]; +int cpu_number_map[NR_CPUS]; +int __cpu_logical_map[NR_CPUS]; extern void calibrate_delay(void); -extern struct thread_struct * original_pcb_ptr; - -static void smp_setup_percpu_timer(void); -static void secondary_cpu_start(int, struct task_struct *); -static void send_cpu_msg(char *, int); +extern asmlinkage void entInt(void); -/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */ + +/* + * Process bootcommand SMP options, like "nosmp" and "maxcpus=". + */ void __init smp_setup(char *str, int *ints) { @@ -102,100 +87,87 @@ max_cpus = 0; } -static void __init -smp_store_cpu_info(int id) +/* + * Called by both boot and secondaries to move global data into + * per-processor storage. + */ +static inline void __init +smp_store_cpu_info(int cpuid) { - /* This is it on Alpha, so far. */ - cpu_data[id].loops_per_sec = loops_per_sec; + cpu_data[cpuid].loops_per_sec = loops_per_sec; } -void __init -smp_commence(void) +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer(int cpuid) { - /* Lets the callin's below out of their loop. */ - mb(); - smp_commenced = 1; + cpu_data[cpuid].prof_counter = 1; + cpu_data[cpuid].prof_multiplier = 1; + +#ifdef NOT_YET_PROFILING + load_profile_irq(mid_xlate[cpu], lvl14_resolution); + if (cpu == smp_boot_cpuid) + enable_pil_irq(14); +#endif } +/* + * Where secondaries begin a life of C. + */ void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif + + /* Turn on machine checks. */ + wrmces(7); + + /* Set trap vectors. */ + trap_init(); + + /* Set interrupt vector. */ + wrent(entInt, 0); + + /* Setup the scheduler for this processor. */ + init_idle(); /* Get our local ticker going. */ - smp_setup_percpu_timer(); + smp_setup_percpu_timer(cpuid); -#if 0 + /* Must have completely accurate bogos. */ + __sti(); calibrate_delay(); -#endif smp_store_cpu_info(cpuid); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif /* Allow master to continue. */ - set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif - -#ifdef NOT_YET - while(!task[cpuid] || current_set[cpuid] != task[cpuid]) - barrier(); -#endif + wmb(); + smp_secondary_alive = cpuid; -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 - __sti(); -#endif -} - -asmlinkage int __init -start_secondary(void *unused) -{ - extern asmlinkage void entInt(void); - extern void paging_init_secondary(void); + /* Wait for the go code. */ + while (!smp_threads_ready) + barrier(); - wrmces(7); - paging_init_secondary(); - trap_init(); - wrent(entInt, 0); + printk(KERN_INFO "SMP: commencing CPU %d current %p\n", + cpuid, current); - smp_callin(); - while (!smp_commenced) - barrier(); -#if 1 - printk("start_secondary: commencing CPU %d current %p\n", - hard_smp_processor_id(), current); -#endif + /* Do nothing. */ cpu_idle(NULL); } + +/* + * Rough estimation for SMP scheduling, this is the number of cycles it + * takes for a fully memory-limited process to flush the SMP-local cache. + * + * We are not told how much cache there is, so we have to guess. + */ static void __init smp_tune_scheduling (void) { - /* - * Rough estimation for SMP scheduling, this is the number of - * cycles it takes for a fully memory-limited process to flush - * the SMP-local cache. - * - * We are not told how much cache there is, so we have to guess. - */ - struct percpu_struct *cpu; unsigned long on_chip_cache; unsigned long freq; @@ -231,259 +203,159 @@ cacheflush_time = freq / 1024 * on_chip_cache / 5000; } - /* - * Cycle through the processors sending START msgs to boot each. + * Send a message to a secondary's console. "START" is one such + * interesting message. ;-) */ -void __init -smp_boot_cpus(void) +static void +send_secondary_console_msg(char *str, int cpuid) { - int cpucount = 0; - int i, first, prev; - - printk("Entering SMP Mode.\n"); - -#if 0 - __sti(); -#endif - - for(i=0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - cpu_logical_map[i] = -1; - prof_counter[i] = 1; - prof_multiplier[i] = 1; - ipi_bits[i] = 0; - } - - cpu_number_map[boot_cpu_id] = 0; - cpu_logical_map[0] = boot_cpu_id; - current->processor = boot_cpu_id; /* ??? */ + struct percpu_struct *cpu; + register char *cp1, *cp2; + unsigned long cpumask; + size_t len; + long timeout; - smp_store_cpu_info(boot_cpu_id); - smp_tune_scheduling(); -#ifdef NOT_YET - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif - smp_setup_percpu_timer(); -#ifdef HUH - local_flush_cache_all(); -#endif - if (smp_num_probed == 1) - return; /* Not an MP box. */ + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + cpuid * hwrpb->processor_size); -#if NOT_YET - /* - * If SMP should be disabled, then really disable it! - */ - if (!max_cpus) - { - smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated.\n"); - } -#endif + cpumask = (1L << cpuid); + if (hwrpb->txrdy & cpumask) + goto delay1; + ready1: - for (i = 0; i < NR_CPUS; i++) { + cp2 = str; + len = strlen(cp2); + *(unsigned int *)&cpu->ipc_buffer[0] = len; + cp1 = (char *) &cpu->ipc_buffer[1]; + memcpy(cp1, cp2, len); - if (i == boot_cpu_id) - continue; + /* atomic test and set */ + wmb(); + set_bit(cpuid, &hwrpb->rxrdy); - if (cpu_present_map & (1 << i)) { - struct task_struct *idle; - int timeout; - - /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_PID); - idle = task[++cpucount]; - if (!idle) - panic("No idle process for CPU %d", i); - idle->processor = i; - - DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n", - i, idle->state, idle->flags)); - - /* whirrr, whirrr, whirrrrrrrrr... */ -#ifdef HUH - local_flush_cache_all(); -#endif - secondary_cpu_start(i, idle); + if (hwrpb->txrdy & cpumask) + goto delay2; + ready2: + return; - /* wheee... it's going... wait for 5 secs...*/ - for (timeout = 0; timeout < 50000; timeout++) { - if (cpu_callin_map[i]) - break; - udelay(100); - } - if (cpu_callin_map[i]) { - /* Another "Red Snapper". */ - cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; - } else { - cpucount--; - printk("smp_boot_cpus: Processor %d" - " is stuck 0x%lx.\n", i, idle->flags); - } - } - if (!(cpu_callin_map[i])) { - cpu_present_map &= ~(1 << i); - cpu_number_map[i] = -1; - } - } -#ifdef HUH - local_flush_cache_all(); -#endif - if (cpucount == 0) { - printk("smp_boot_cpus: ERROR - only one Processor found.\n"); - cpu_present_map = (1 << smp_processor_id()); - } else { - unsigned long bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_map & (1 << i)) - bogosum += cpu_data[i].loops_per_sec; - } - printk("smp_boot_cpus: Total of %d Processors activated" - " (%lu.%02lu BogoMIPS).\n", - cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); - smp_activated = 1; - smp_num_cpus = cpucount + 1; +delay1: + /* Wait one second. Note that jiffies aren't ticking yet. */ + for (timeout = 100000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready1; + udelay(10); + barrier(); } + goto timeout; - /* Setup CPU list for IRQ distribution scheme. */ - first = prev = -1; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_map & (1 << i)) { - if (first == -1) - first = i; - if (prev != -1) - cpu_data[i].next = i; - prev = i; - } +delay2: + /* Wait one second. */ + for (timeout = 100000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready2; + udelay(10); + barrier(); } - cpu_data[prev].next = first; + goto timeout; - /* Ok, they are spinning and ready to go. */ - smp_processors_ready = 1; +timeout: + printk("Processor %x not ready\n", cpuid); + return; } -static void __init -smp_setup_percpu_timer(void) +/* + * A secondary console wants to send a message. Receive it. + */ +static void +recv_secondary_console_msg(void) { - int cpu = smp_processor_id(); - - prof_counter[cpu] = prof_multiplier[cpu] = 1; -#ifdef NOT_YET - load_profile_irq(mid_xlate[cpu], lvl14_resolution); - if (cpu == boot_cpu_id) - enable_pil_irq(14); -#endif -} - -extern void update_one_process(struct task_struct *p, unsigned long ticks, - unsigned long user, unsigned long system, - int cpu); + int mycpu, i, cnt; + unsigned long txrdy = hwrpb->txrdy; + char *cp1, *cp2, buf[80]; + struct percpu_struct *cpu; -void -smp_percpu_timer_interrupt(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); + DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy)); -#ifdef NOT_YET - clear_profile_irq(mid_xlate[cpu]); - if(!user_mode(regs)) - alpha_do_profile(regs->pc); -#endif + mycpu = hard_smp_processor_id(); - if (!--prof_counter[cpu]) { - int user = user_mode(regs); - if (current->pid) { - update_one_process(current, 1, user, !user, cpu); + for (i = 0; i < NR_CPUS; i++) { + if (!(txrdy & (1L << i))) + continue; - if (--current->counter < 0) { - current->counter = 0; - current->need_resched = 1; - } + DBGS(("recv_secondary_console_msg: " + "TXRDY contains CPU %d.\n", i)); - spin_lock(&ticker_lock); - if (user) { - if (current->priority < DEF_PRIORITY) { - kstat.cpu_nice++; - kstat.per_cpu_nice[cpu]++; - } else { - kstat.cpu_user++; - kstat.per_cpu_user[cpu]++; - } - } else { - kstat.cpu_system++; - kstat.per_cpu_system[cpu]++; - } - spin_unlock(&ticker_lock); - } - prof_counter[cpu] = prof_multiplier[cpu]; - } -} + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + i * hwrpb->processor_size); -int __init -setup_profiling_timer(unsigned int multiplier) -{ -#ifdef NOT_YET - int i; - unsigned long flags; + printk(KERN_INFO "recv_secondary_console_msg: on %d from %d" + " HALT_REASON 0x%lx FLAGS 0x%lx\n", + mycpu, i, cpu->halt_reason, cpu->flags); - /* Prevent level14 ticker IRQ flooding. */ - if((!multiplier) || (lvl14_resolution / multiplier) < 500) - return -EINVAL; + cnt = cpu->ipc_buffer[0] >> 32; + if (cnt <= 0 || cnt >= 80) + strcpy(buf, "<<< BOGUS MSG >>>"); + else { + cp1 = (char *) &cpu->ipc_buffer[11]; + cp2 = buf; + strcpy(cp2, cp1); + + while ((cp2 = strchr(cp2, '\r')) != 0) { + *cp2 = ' '; + if (cp2[1] == '\n') + cp2[1] = ' '; + } + } - save_and_cli(flags); - for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1 << i)) { - load_profile_irq(mid_xlate[i], lvl14_resolution / multip -lier); - prof_multiplier[i] = multiplier; - } + printk(KERN_INFO "recv_secondary_console_msg: on %d " + "message is '%s'\n", mycpu, buf); } - restore_flags(flags); - return 0; - -#endif - return -EINVAL; -} - -/* Only broken Intel needs this, thus it should not even be - referenced globally. */ - -void __init -initialize_secondary(void) -{ + hwrpb->txrdy = 0; } -static void __init +/* + * Convince the console to have a secondary cpu begin execution. + */ +static int __init secondary_cpu_start(int cpuid, struct task_struct *idle) { struct percpu_struct *cpu; - int timeout; + struct pcb_struct *hwpcb; + long timeout; cpu = (struct percpu_struct *) ((char*)hwrpb + hwrpb->processor_offset + cpuid * hwrpb->processor_size); + hwpcb = (struct pcb_struct *) cpu->hwpcb; - /* Set context to idle thread this CPU will use when running - assumption is that the idle thread is all set to go... ??? */ - memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct)); - cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */ + /* Initialize the CPU's HWPCB to something just good enough for + us to get started. Immediately after starting, we'll swpctx + to the target idle task's tss. Reuse the stack in the mean + time. Precalculate the target PCBB. */ + hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16; + hwpcb->usp = 0; + hwpcb->ptbr = idle->tss.ptbr; + hwpcb->pcc = 0; + hwpcb->asn = 0; + hwpcb->unique = virt_to_phys(&idle->tss); + hwpcb->flags = idle->tss.pal_flags; + hwpcb->res1 = hwpcb->res2 = 0; - DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n", - cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb)); + DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n", + hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique)); DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", cpuid, idle->state, idle->tss.pal_flags)); /* Setup HWRPB fields that SRM uses to activate secondary CPU */ - hwrpb->CPU_restart = __start_cpu; - hwrpb->CPU_restart_data = (unsigned long) idle; + hwrpb->CPU_restart = __smp_callin; + hwrpb->CPU_restart_data = (unsigned long) __smp_callin; /* Recalculate and update the HWRPB checksum */ hwrpb_update_checksum(hwrpb); @@ -495,99 +367,97 @@ /* SRM III 3.4.1.3 */ cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */ cpu->flags &= ~1; /* turn off Bootstrap In Progress */ - mb(); + wmb(); - send_cpu_msg("START\r\n", cpuid); + send_secondary_console_msg("START\r\n", cpuid); - /* now, we wait... */ - for (timeout = 10000; !(cpu->flags & 1); timeout--) { - if (timeout <= 0) { - printk("Processor %d failed to start\n", cpuid); - /* needed for pset_info to work */ -#if 0 - ipc_processor_enable(cpu_to_processor(cpunum)); -#endif - return; - } - mdelay(1); + /* Wait 1 second for an ACK from the console. Note that jiffies + aren't ticking yet. */ + for (timeout = 100000; timeout > 0; timeout--) { + if (cpu->flags & 1) + goto started; + udelay(10); barrier(); } + printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid); + return -1; + +started: DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid)); + return 0; } -static void -send_cpu_msg(char *str, int cpuid) +/* + * Bring one cpu online. + */ +static int __init +smp_boot_one_cpu(int cpuid, int cpunum) { - struct percpu_struct *cpu; - register char *cp1, *cp2; - unsigned long cpumask; - size_t len; - int timeout; - - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + cpuid * hwrpb->processor_size); - - cpumask = (1L << cpuid); - if (hwrpb->txrdy & cpumask) - goto delay1; - ready1: - - cp2 = str; - len = strlen(cp2); - *(unsigned int *)&cpu->ipc_buffer[0] = len; - cp1 = (char *) &cpu->ipc_buffer[1]; - memcpy(cp1, cp2, len); - - /* atomic test and set */ - set_bit(cpuid, &hwrpb->rxrdy); + struct task_struct *idle; + long timeout; - if (hwrpb->txrdy & cpumask) - goto delay2; - ready2: - return; - -delay1: - for (timeout = 10000; timeout > 0; --timeout) { - if (!(hwrpb->txrdy & cpumask)) - goto ready1; - udelay(100); + /* Cook up an idler for this guy. Note that the address we give + to kernel_thread is irrelevant -- it's going to start where + HWRPB.CPU_restart says to start. But this gets all the other + task-y sort of data structures set up like we wish. */ + kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM); + idle = task[cpunum]; + if (!idle) + panic("No idle process for CPU %d", cpuid); + idle->processor = cpuid; + + /* Schedule the first task manually. */ + /* ??? Ingo, what is this? */ + idle->has_cpu = 1; + + DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", + cpuid, idle->state, idle->flags)); + + /* The secondary will change this once it is happy. Note that + secondary_cpu_start contains the necessary memory barrier. */ + smp_secondary_alive = -1; + + /* Whirrr, whirrr, whirrrrrrrrr... */ + if (secondary_cpu_start(cpuid, idle)) + return -1; + + /* We've been acked by the console; wait one second for the task + to start up for real. Note that jiffies aren't ticking yet. */ + for (timeout = 0; timeout < 100000; timeout++) { + if (smp_secondary_alive != -1) + goto alive; + udelay(10); barrier(); } - goto timeout; - -delay2: - for (timeout = 10000; timeout > 0; --timeout) { - if (!(hwrpb->txrdy & cpumask)) - goto ready2; - udelay(100); - barrier(); - } - goto timeout; -timeout: - printk("Processor %x not ready\n", cpuid); - return; + printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); + return -1; + +alive: + /* Another "Red Snapper". */ + cpu_number_map[cpuid] = cpunum; + __cpu_logical_map[cpunum] = cpuid; + return 0; } /* - * setup_smp() - * - * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined + * Called from setup_arch. Detect an SMP system and which processors + * are present. */ void __init setup_smp(void) { struct percpu_struct *cpubase, *cpu; int i; - - boot_cpu_id = hard_smp_processor_id(); - if (boot_cpu_id != 0) { - printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id); + + smp_boot_cpuid = hard_smp_processor_id(); + if (smp_boot_cpuid != 0) { + printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n", + smp_boot_cpuid); } if (hwrpb->nr_processors > 1) { + int boot_cpu_palrev; DBGS(("setup_smp: nr_processors %ld\n", hwrpb->nr_processors)); @@ -601,10 +471,9 @@ ((char *)cpubase + i*hwrpb->processor_size); if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; - /* assume here that "whami" == index */ - cpu_present_map |= (1 << i); - if (i != boot_cpu_id) - cpu->pal_revision = boot_cpu_palrev; + /* Assume here that "whami" == index */ + cpu_present_mask |= (1L << i); + cpu->pal_revision = boot_cpu_palrev; } DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n", @@ -614,76 +483,249 @@ } } else { smp_num_probed = 1; - cpu_present_map = (1 << boot_cpu_id); + cpu_present_mask = (1L << smp_boot_cpuid); } - printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x," - " boot_cpu_id %d\n", - smp_num_probed, cpu_present_map, boot_cpu_id); + + printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", + smp_num_probed, cpu_present_mask); } -static void -secondary_console_message(void) +/* + * Called by smp_init bring all the secondaries online and hold them. + */ +void __init +smp_boot_cpus(void) { - int mycpu, i, cnt; - unsigned long txrdy = hwrpb->txrdy; - char *cp1, *cp2, buf[80]; - struct percpu_struct *cpu; + int cpu_count, i; + unsigned long bogosum; - DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy)); + /* Take care of some initial bookkeeping. */ + memset(cpu_number_map, -1, sizeof(cpu_number_map)); + memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map)); + memset(ipi_data, 0, sizeof(ipi_data)); + + cpu_number_map[smp_boot_cpuid] = 0; + __cpu_logical_map[0] = smp_boot_cpuid; + current->processor = smp_boot_cpuid; - mycpu = hard_smp_processor_id(); + smp_store_cpu_info(smp_boot_cpuid); + smp_tune_scheduling(); + smp_setup_percpu_timer(smp_boot_cpuid); + + init_idle(); + + /* Nothing to do on a UP box, or when told not to. */ + if (smp_num_probed == 1 || max_cpus == 0) { + printk(KERN_INFO "SMP mode deactivated.\n"); + return; + } + printk(KERN_INFO "SMP starting up secondaries.\n"); + + cpu_count = 1; for (i = 0; i < NR_CPUS; i++) { - if (!(txrdy & (1L << i))) + if (i == smp_boot_cpuid) continue; - DBGS(("secondary_console_message: " - "TXRDY contains CPU %d.\n", i)); + if (((cpu_present_mask >> i) & 1) == 0) + continue; - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + i * hwrpb->processor_size); + if (smp_boot_one_cpu(i, cpu_count)) + continue; - printk("secondary_console_message: on %d from %d" - " HALT_REASON 0x%lx FLAGS 0x%lx\n", - mycpu, i, cpu->halt_reason, cpu->flags); + cpu_count++; + } - cnt = cpu->ipc_buffer[0] >> 32; - if (cnt <= 0 || cnt >= 80) - strcpy(buf, "<<< BOGUS MSG >>>"); - else { - cp1 = (char *) &cpu->ipc_buffer[11]; - cp2 = buf; - strcpy(cp2, cp1); - - while ((cp2 = strchr(cp2, '\r')) != 0) { - *cp2 = ' '; - if (cp2[1] == '\n') - cp2[1] = ' '; - } - } + if (cpu_count == 1) { + printk(KERN_ERR "SMP: Only one lonely processor alive.\n"); + return; + } + + bogosum = 0; + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_mask & (1L << i)) + bogosum += cpu_data[i].loops_per_sec; + } + printk(KERN_INFO "SMP: Total of %d processors activated " + "(%lu.%02lu BogoMIPS).\n", + cpu_count, (bogosum + 2500) / 500000, + ((bogosum + 2500) / 5000) % 100); + + smp_num_cpus = cpu_count; +} + +/* + * Called by smp_init to release the blocking online cpus once they + * are all started. + */ +void __init +smp_commence(void) +{ + /* smp_init sets smp_threads_ready -- that's enough. */ + mb(); +} + +/* + * Only broken Intel needs this, thus it should not even be + * referenced globally. + */ + +void __init +initialize_secondary(void) +{ +} + + +extern void update_one_process(struct task_struct *p, unsigned long ticks, + unsigned long user, unsigned long system, + int cpu); + +void +smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int user = user_mode(regs); + struct cpuinfo_alpha *data = &cpu_data[cpu]; + +#ifdef NOT_YET_PROFILING + clear_profile_irq(mid_xlate[cpu]); + if (!user) + alpha_do_profile(regs->pc); +#endif + + if (!--data->prof_counter) { + /* We need to make like a normal interrupt -- otherwise + timer interrupts ignore the global interrupt lock, + which would be a Bad Thing. */ + irq_enter(cpu, TIMER_IRQ); + + update_one_process(current, 1, user, !user, cpu); + if (current->pid) { + if (--current->counter < 0) { + current->counter = 0; + current->need_resched = 1; + } + + if (user) { + if (current->priority < DEF_PRIORITY) { + kstat.cpu_nice++; + kstat.per_cpu_nice[cpu]++; + } else { + kstat.cpu_user++; + kstat.per_cpu_user[cpu]++; + } + } else { + kstat.cpu_system++; + kstat.per_cpu_system[cpu]++; + } + } - printk("secondary_console_message: on %d message is '%s'\n", - mycpu, buf); + data->prof_counter = data->prof_multiplier; + irq_exit(cpu, TIMER_IRQ); } +} - hwrpb->txrdy = 0; +int __init +setup_profiling_timer(unsigned int multiplier) +{ +#ifdef NOT_YET_PROFILING + int i; + unsigned long flags; + + /* Prevent level14 ticker IRQ flooding. */ + if((!multiplier) || (lvl14_resolution / multiplier) < 500) + return -EINVAL; + + save_and_cli(flags); + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_mask & (1L << i)) { + load_profile_irq(mid_xlate[i], + lvl14_resolution / multiplier); + prof_multiplier[i] = multiplier; + } + } + restore_flags(flags); + + return 0; +#else + return -EINVAL; +#endif } -enum ipi_message_type { - IPI_TLB_ALL, - IPI_TLB_MM, - IPI_TLB_PAGE, - IPI_RESCHEDULE, - IPI_CPU_STOP + +static void +send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) +{ + long i, j; + + /* Reduce the number of memory barriers by doing two loops, + one to set the bits, one to invoke the interrupts. */ + + mb(); /* Order out-of-band data and bit setting. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + set_bit(operation, &ipi_data[i].bits); + } + + mb(); /* Order bit setting and interrupt. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + wripir(i); + } +} + +/* Structure and data for smp_call_function. This is designed to + minimize static memory requirements. Plus it looks cleaner. */ + +struct smp_call_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t unstarted_count; + atomic_t unfinished_count; }; +static struct smp_call_struct *smp_call_function_data; + +/* Atomicly drop data into a shared pointer. The pointer is free if + it is initially locked. If retry, spin until free. */ + +static inline int +pointer_lock (void *lock, void *data, int retry) +{ + void *old, *tmp; + + mb(); +again: + /* Compare and swap with zero. */ + asm volatile ( + "1: ldq_l %0,%1\n" + " mov %3,%2\n" + " bne %0,2f\n" + " stq_c %2,%1\n" + " beq %2,1b\n" + "2:" + : "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp) + : "r"(data) + : "memory"); + + if (old == 0) + return 0; + if (! retry) + return -EBUSY; + + while (*(void **)lock) + schedule(); + goto again; +} + void handle_ipi(struct pt_regs *regs) { int this_cpu = smp_processor_id(); - volatile int * pending_ipis = &ipi_bits[this_cpu]; + unsigned long *pending_ipis = &ipi_data[this_cpu].bits; unsigned long ops; DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", @@ -699,190 +741,189 @@ ops &= ~which; which = ffz(~which); - if (which < IPI_RESCHEDULE) { - if (which == IPI_TLB_ALL) - tbia(); - else if (which == IPI_TLB_MM) { - struct mm_struct * mm; - mm = ipi_msg_flush_tb.p.flush_mm; - if (mm == current->mm) - flush_tlb_current(mm); - } - else /* IPI_TLB_PAGE */ { - struct vm_area_struct * vma; - struct mm_struct * mm; - unsigned long addr; - - vma = ipi_msg_flush_tb.p.flush_vma; - mm = vma->vm_mm; - addr = ipi_msg_flush_tb.flush_addr; - - if (mm == current->mm) - flush_tlb_current_page(mm, vma, addr); - } - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - } - else if (which == IPI_RESCHEDULE) { + if (which == IPI_RESCHEDULE) { /* Reschedule callback. Everything to be done is done by the interrupt return path. */ } + else if (which == IPI_CALL_FUNC) { + struct smp_call_struct *data; + void (*func)(void *info); + void *info; + int wait; + + data = smp_call_function_data; + func = data->func; + info = data->info; + wait = data->wait; + + /* Notify the sending CPU that the data has been + received, and execution is about to begin. */ + mb(); + atomic_dec (&data->unstarted_count); + + /* At this point the structure may be gone unless + wait is true. */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) atomic_dec (&data->unfinished_count); + } else if (which == IPI_CPU_STOP) { halt(); } else { - printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n", + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); } } while (ops); + mb(); /* Order data access and bit testing. */ } cpu_data[this_cpu].ipi_count++; if (hwrpb->txrdy) - secondary_console_message(); + recv_secondary_console_msg(); } -static void -send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) +void +smp_send_reschedule(int cpu) { - long i, j; - - /* Reduce the number of memory barriers by doing two loops, - one to set the bits, one to invoke the interrupts. */ - - mb(); /* Order out-of-band data and bit setting. */ - - for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { - if (to_whom & j) - set_bit(operation, &ipi_bits[i]); - } - - mb(); /* Order bit setting and interrupt. */ + send_ipi_message(1L << cpu, IPI_RESCHEDULE); +} - for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { - if (to_whom & j) - wripir(i); - } +void +smp_send_stop(void) +{ + unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + send_ipi_message(to_whom, IPI_CPU_STOP); } +/* + * Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute + * or are or have executed. + */ + int -smp_info(char *buffer) +smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { - long i; - unsigned long sum = 0; - for (i = 0; i < NR_CPUS; i++) - sum += cpu_data[i].ipi_count; + unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + struct smp_call_struct data; + long timeout; + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, smp_num_cpus - 1); + atomic_set(&data.unfinished_count, smp_num_cpus - 1); + + /* Aquire the smp_call_function_data mutex. */ + if (pointer_lock(&smp_call_function_data, &data, retry)) + return -EBUSY; + + /* Send a message to all other CPUs. */ + send_ipi_message(to_whom, IPI_CALL_FUNC); + + /* Wait for a minimal response. */ + timeout = jiffies + HZ; + while (atomic_read (&data.unstarted_count) > 0 + && time_before (jiffies, timeout)) + barrier(); - return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n", - smp_num_probed, smp_num_cpus, cpu_present_map, sum); -} + /* We either got one or timed out -- clear the lock. */ + mb(); + smp_call_function_data = 0; + if (atomic_read (&data.unstarted_count) > 0) + return -ETIMEDOUT; + + /* Wait for a complete response, if needed. */ + if (wait) { + while (atomic_read (&data.unfinished_count) > 0) + barrier(); + } -void -smp_send_reschedule(int cpu) -{ - send_ipi_message(1 << cpu, IPI_RESCHEDULE); + return 0; } -void -smp_send_stop(void) +static void +ipi_flush_tlb_all(void *ignored) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - send_ipi_message(to_whom, IPI_CPU_STOP); + tbia(); } void flush_tlb_all(void) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, IPI_TLB_ALL); tbia(); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); - } - - if (timeout == 0) { - printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; + /* Although we don't have any data to pass, we do want to + synchronize with the other processors. */ + if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) { + printk(KERN_CRIT "flush_tlb_all: timed out\n"); } +} - spin_unlock(&flush_tb_lock); +static void +ipi_flush_tlb_mm(void *x) +{ + struct mm_struct *mm = (struct mm_struct *) x; + if (mm == current->mm) + flush_tlb_current(mm); } void flush_tlb_mm(struct mm_struct *mm) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - ipi_msg_flush_tb.p.flush_mm = mm; - send_ipi_message(to_whom, IPI_TLB_MM); - - if (mm != current->mm) - flush_tlb_other(mm); - else + if (mm == current->mm) flush_tlb_current(mm); + else + flush_tlb_other(mm); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); + if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) { + printk(KERN_CRIT "flush_tlb_mm: timed out\n"); } +} - if (timeout == 0) { - printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - } +struct flush_tlb_page_struct { + struct vm_area_struct *vma; + struct mm_struct *mm; + unsigned long addr; +}; - spin_unlock(&flush_tb_lock); +static void +ipi_flush_tlb_page(void *x) +{ + struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x; + if (data->mm == current->mm) + flush_tlb_current_page(data->mm, data->vma, data->addr); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - int cpu = smp_processor_id(); - unsigned long to_whom = cpu_present_map ^ (1 << cpu); - struct mm_struct * mm = vma->vm_mm; - int timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - ipi_msg_flush_tb.p.flush_vma = vma; - ipi_msg_flush_tb.flush_addr = addr; - send_ipi_message(to_whom, IPI_TLB_PAGE); - - if (mm != current->mm) - flush_tlb_other(mm); - else - flush_tlb_current_page(mm, vma, addr); + struct flush_tlb_page_struct data; + struct mm_struct *mm = vma->vm_mm; - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); - } + data.vma = vma; + data.mm = mm; + data.addr = addr; - if (timeout == 0) { - printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; + if (mm == current->mm) + flush_tlb_current_page(mm, vma, addr); + else + flush_tlb_other(mm); + + if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) { + printk(KERN_CRIT "flush_tlb_page: timed out\n"); } - - spin_unlock(&flush_tb_lock); } void @@ -892,6 +933,20 @@ flush_tlb_mm(mm); } + +int +smp_info(char *buffer) +{ + long i; + unsigned long sum = 0; + for (i = 0; i < NR_CPUS; i++) + sum += cpu_data[i].ipi_count; + + return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n", + smp_num_probed, smp_num_cpus, cpu_present_mask, sum); +} + + #if DEBUG_SPINLOCK #ifdef MANAGE_SPINLOCK_IPL @@ -932,17 +987,16 @@ spin_lock(spinlock_t * lock) { long tmp; - long stuck = 1<<27; + long stuck; void *inline_pc = __builtin_return_address(0); unsigned long started = jiffies; int printed = 0; int cpu = smp_processor_id(); long old_ipl = spinlock_raise_ipl(lock); + stuck = 1L << 28; try_again: - stuck = 0x10000000; /* was 4G, now 256M */ - /* Use sub-sections to put the actual loop at the end of this object file's text section so as to perfect branch prediction. */ @@ -961,19 +1015,16 @@ " blbs %0,2b\n" " br 1b\n" ".previous" - : "=r" (tmp), - "=m" (__dummy_lock(lock)), - "=r" (stuck) - : "2" (stuck)); + : "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck) + : "1" (__dummy_lock(lock)), "2" (stuck)); if (stuck < 0) { - if (!printed) { - printk("spinlock stuck at %p(%d) owner %s at %p\n", - inline_pc, cpu, lock->task->comm, - lock->previous); - printed = 1; - } - stuck = 1<<30; + printk(KERN_WARNING + "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n", + inline_pc, cpu, lock->task->comm, lock->previous, + lock->task->processor, lock->task->state); + stuck = 1L << 36; + printed = 1; goto try_again; } @@ -984,7 +1035,7 @@ lock->task = current; if (printed) { - printk("spinlock grabbed at %p(%d) %ld ticks\n", + printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n", inline_pc, cpu, jiffies - started); } } @@ -1006,7 +1057,7 @@ return ret; } #endif /* DEBUG_SPINLOCK */ - + #if DEBUG_RWLOCK void write_lock(rwlock_t * lock) { @@ -1038,18 +1089,17 @@ " blt %1,8b\n" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy) - , "=&r" (stuck_lock), "=&r" (stuck_reader) - : "0" (__dummy_lock(lock)) - , "3" (stuck_lock), "4" (stuck_reader) - ); + : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy), + "=&r" (stuck_lock), "=&r" (stuck_reader) + : "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader)); if (stuck_lock < 0) { - printk("write_lock stuck at %p\n", inline_pc); + printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); goto try_again; } if (stuck_reader < 0) { - printk("write_lock stuck on readers at %p\n", inline_pc); + printk(KERN_WARNING "write_lock stuck on readers at %p\n", + inline_pc); goto try_again; } } @@ -1079,11 +1129,10 @@ " br 1b\n" ".previous" : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock) - : "0" (__dummy_lock(lock)), "2" (stuck_lock) - ); + : "0" (__dummy_lock(lock)), "2" (stuck_lock)); if (stuck_lock < 0) { - printk("read_lock stuck at %p\n", inline_pc); + printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); goto try_again; } } diff -ur --new-file old/linux/arch/alpha/kernel/time.c new/linux/arch/alpha/kernel/time.c --- old/linux/arch/alpha/kernel/time.c Sun Apr 25 02:54:08 1999 +++ new/linux/arch/alpha/kernel/time.c Fri May 14 21:41:23 1999 @@ -42,6 +42,9 @@ #include "proto.h" #include "irq.h" +extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + static int set_rtc_mmss(unsigned long); @@ -86,15 +89,15 @@ long nticks; #ifdef __SMP__ - extern void smp_percpu_timer_interrupt(struct pt_regs *); - extern unsigned int boot_cpu_id; - /* when SMP, do this for *all* CPUs, - but only do the rest for the boot CPU */ + /* When SMP, do this for *all* CPUs, but only do the rest for + the boot CPU. */ smp_percpu_timer_interrupt(regs); - if (smp_processor_id() != boot_cpu_id) - return; + if (smp_processor_id() != smp_boot_cpuid) + return; #endif + write_lock(&xtime_lock); + /* * Calculate how many ticks have passed since the last update, * including any previous partial leftover. Save any resulting @@ -124,6 +127,8 @@ int tmp = set_rtc_mmss(xtime.tv_sec); state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0); } + + write_unlock(&xtime_lock); } /* @@ -226,7 +231,8 @@ { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq, diff, one_percent; + unsigned long cycle_freq, one_percent; + long diff; /* * The Linux interpretation of the CMOS clock register contents: @@ -242,7 +248,7 @@ if (!est_cycle_freq) { /* Sometimes the hwrpb->cycle_freq value is bogus. - Go another round to check up on it and see. */ + Go another round to check up on it and see. */ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); @@ -279,8 +285,7 @@ mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); @@ -328,18 +333,24 @@ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, delta_cycles, delta_usec; - unsigned long sec, usec; - __u32 now; - extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + unsigned long sec, usec, lost, flags; + unsigned long delta_cycles, delta_usec, partial_tick; - now = rpcc(); - save_and_cli(flags); + read_lock_irqsave(&xtime_lock, flags); + + delta_cycles = rpcc() - state.last_time; sec = xtime.tv_sec; usec = xtime.tv_usec; - delta_cycles = now - state.last_time; - restore_flags(flags); + partial_tick = state.partial_tick; + lost = lost_ticks; + + read_unlock_irqrestore(&xtime_lock, flags); +#ifdef __SMP__ + /* Until and unless we figure out how to get cpu cycle counters + in sync and keep them there, we can't use the rpcc tricks. */ + delta_usec = lost * (1000000 / HZ); +#else /* * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks) * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks) @@ -354,13 +365,10 @@ */ delta_usec = (delta_cycles * state.scaled_ticks_per_cycle - + state.partial_tick - + (lost_ticks << FIX_SHIFT) ) * 15625; + + partial_tick + + (lost << FIX_SHIFT)) * 15625; delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; - - /* the 'lost_tics' term above implements this: - * delta_usec += lost_ticks * (1000000 / HZ); - */ +#endif usec += delta_usec; if (usec >= 1000000) { @@ -375,13 +383,41 @@ void do_settimeofday(struct timeval *tv) { - cli(); - xtime = *tv; + unsigned long delta_usec; + long sec, usec; + + write_lock_irq(&xtime_lock); + + /* The offset that is added into time in do_gettimeofday above + must be subtracted out here to keep a coherent view of the + time. Without this, a full-tick error is possible. */ + +#ifdef __SMP__ + delta_usec = lost_ticks * (1000000 / HZ); +#else + delta_usec = rpcc() - state.last_time; + delta_usec = (delta_usec * state.scaled_ticks_per_cycle + + state.partial_tick + + (lost_ticks << FIX_SHIFT)) * 15625; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; +#endif + + sec = tv->tv_sec; + usec = tv->tv_usec; + usec -= delta_usec; + if (usec < 0) { + usec += 1000000; + sec -= 1; + } + + xtime.tv_sec = sec; + xtime.tv_usec = usec; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + + write_unlock_irq(&xtime_lock); } diff -ur --new-file old/linux/arch/alpha/kernel/traps.c new/linux/arch/alpha/kernel/traps.c --- old/linux/arch/alpha/kernel/traps.c Mon May 10 18:55:21 1999 +++ new/linux/arch/alpha/kernel/traps.c Fri May 14 21:41:23 1999 @@ -1,5 +1,5 @@ /* - * kernel/traps.c + * arch/alpha/kernel/traps.c * * (C) Copyright 1994 Linus Torvalds */ @@ -95,6 +95,9 @@ { if (regs->ps & 8) return; +#ifdef __SMP__ + printk("CPU %d ", hard_smp_processor_id()); +#endif printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); dik_show_regs(regs, r9_15); dik_show_code((unsigned int *)regs->pc); @@ -128,8 +131,8 @@ if (summary & 1) { /* Software-completion summary bit is set, so try to emulate the instruction. */ - if (implver() == IMPLVER_EV6) { - /* Whee! EV6 has precice exceptions. */ + if (!amask(AMASK_PRECISE_TRAP)) { + /* 21264 (except pass 1) has precise exceptions. */ if (alpha_fp_emul(regs.pc - 4)) return; } else { @@ -138,14 +141,12 @@ } } - lock_kernel(); #if 0 printk("%s: arithmetic trap at %016lx: %02lx %016lx\n", current->comm, regs.pc, summary, write_mask); #endif die_if_kernel("Arithmetic fault", ®s, 0, 0); send_sig(SIGFPE, current, 1); - unlock_kernel(); } asmlinkage void @@ -235,10 +236,8 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - lock_kernel(); die_if_kernel("Instruction fault", ®s, type, 0); force_sig(SIGILL, current); - unlock_kernel(); } @@ -453,10 +452,8 @@ unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); - lock_kernel(); printk("Forwarding unaligned exception at %lx (%lx)\n", pc, newpc); - unlock_kernel(); (®s)->pc = newpc; return; @@ -610,11 +607,9 @@ cnt = 0; } if (++cnt < 5) { - lock_kernel(); printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", current->comm, current->pid, regs->pc - 4, va, opcode, reg); - unlock_kernel(); } last_time = jiffies; } @@ -868,16 +863,12 @@ give_sigsegv: regs->pc -= 4; /* make pc point to faulting insn */ - lock_kernel(); send_sig(SIGSEGV, current, 1); - unlock_kernel(); return; give_sigbus: regs->pc -= 4; - lock_kernel(); send_sig(SIGBUS, current, 1); - unlock_kernel(); return; } diff -ur --new-file old/linux/arch/alpha/mm/init.c new/linux/arch/alpha/mm/init.c --- old/linux/arch/alpha/mm/init.c Mon Oct 12 20:40:12 1998 +++ new/linux/arch/alpha/mm/init.c Fri May 14 21:41:23 1999 @@ -256,26 +256,6 @@ return start_mem; } -#ifdef __SMP__ -/* - * paging_init_secondary(), called ONLY by secondary CPUs, - * sets up current->tss contents appropriately and does a load_PCB. - * note that current should be pointing at the idle thread task struct - * for this CPU. - */ -void -paging_init_secondary(void) -{ - current->tss.ptbr = init_task.tss.ptbr; - current->tss.pal_flags = 1; - current->tss.flags = 0; - load_PCB(¤t->tss); - tbia(); - - return; -} -#endif /* __SMP__ */ - #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) void srm_paging_stop (void) diff -ur --new-file old/linux/arch/i386/Makefile new/linux/arch/i386/Makefile --- old/linux/arch/i386/Makefile Wed Dec 30 23:17:25 1998 +++ new/linux/arch/i386/Makefile Sun May 16 22:17:22 1999 @@ -25,22 +25,27 @@ ifdef CONFIG_M386 CFLAGS := $(CFLAGS) -m386 -DCPU=386 +AFLAGS := $(AFLAGS) -DCPU=386 endif ifdef CONFIG_M486 CFLAGS := $(CFLAGS) -m486 -DCPU=486 +AFLAGS := $(AFLAGS) -DCPU=486 endif ifdef CONFIG_M586 -CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 +CFLAGS := $(CFLAGS) -DCPU=586 +AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_M586TSC -CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 +CFLAGS := $(CFLAGS) -DCPU=586 +AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_M686 -CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 +CFLAGS := $(CFLAGS) -DCPU=686 +AFLAGS := $(AFLAGS) -DCPU=686 endif HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o diff -ur --new-file old/linux/arch/i386/boot/video.S new/linux/arch/i386/boot/video.S --- old/linux/arch/i386/boot/video.S Wed Sep 30 06:03:35 1998 +++ new/linux/arch/i386/boot/video.S Fri May 14 21:47:01 1999 @@ -1,14 +1,19 @@ ! -! Display adapter & video mode setup, version 2.12 (25-May-98) +! Display adapter & video mode setup, version 2.13 (14-May-99) ! -! Copyright (C) 1995 -- 1998 Martin Mares +! Copyright (C) 1995 -- 1999 Martin Mares ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson ! +! For further information, look at Documentation/svga.txt. +! #include /* for CONFIG_VIDEO_* */ ! Enable autodetection of SVGA adapters and modes. If you really need this -! feature, drop me a mail as I think of removing it some day... +! feature, drop me a mail as I think of removing it some day. You can +! always enter `scan' to get the video mode table and then use the real +! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu +! item numbers) which don't rely on any autodetection. #undef CONFIG_VIDEO_SVGA ! Enable autodetection of VESA modes @@ -1939,7 +1944,7 @@ badmdt: .ascii "You passed an undefined mode number." db 0x0d, 0x0a, 0 vesaer: .ascii "Error: Scanning of VESA modes failed. Please " - .ascii "report to ." + .ascii "report to ." db 0x0d, 0x0a, 0 old_name: .ascii "CGA/MDA/HGA" db 0 diff -ur --new-file old/linux/arch/i386/config.in new/linux/arch/i386/config.in --- old/linux/arch/i386/config.in Thu Jun 3 04:26:57 1999 +++ new/linux/arch/i386/config.in Thu Jun 3 04:28:25 1999 @@ -171,7 +171,7 @@ source drivers/char/Config.in -# source drivers/usb/Config.in +source drivers/usb/Config.in source fs/Config.in diff -ur --new-file old/linux/arch/i386/defconfig new/linux/arch/i386/defconfig --- old/linux/arch/i386/defconfig Mon Apr 12 22:12:57 1999 +++ new/linux/arch/i386/defconfig Sat May 15 03:27:32 1999 @@ -73,7 +73,9 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y +# CONFIG_IDECD_SLOTS is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set @@ -83,6 +85,7 @@ CONFIG_BLK_DEV_IDEPCI=y CONFIG_BLK_DEV_IDEDMA=y # CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_AEC6210 is not set CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set @@ -96,6 +99,7 @@ # CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set +CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_BLK_DEV_HD is not set # @@ -290,6 +294,18 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set + +# +# USB drivers - not for the faint of heart +# +CONFIG_USB=y +CONFIG_USB_UHCI=y +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_MOUSE=y +CONFIG_USB_KBD=y +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ACM is not set # # Filesystems diff -ur --new-file old/linux/arch/i386/kernel/apm.c new/linux/arch/i386/kernel/apm.c --- old/linux/arch/i386/kernel/apm.c Fri Jan 15 07:57:25 1999 +++ new/linux/arch/i386/kernel/apm.c Fri May 14 08:22:05 1999 @@ -314,7 +314,7 @@ static int debug = 0; static int apm_disabled = 0; -static struct wait_queue * process_list = NULL; +static DECLARE_WAIT_QUEUE_HEAD(process_list); static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; @@ -1017,7 +1017,7 @@ struct apm_bios_struct * as; int i; apm_event_t event; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); as = fp->private_data; if (check_apm_bios_struct(as, "read")) diff -ur --new-file old/linux/arch/i386/kernel/init_task.c new/linux/arch/i386/kernel/init_task.c --- old/linux/arch/i386/kernel/init_task.c Sun Sep 13 21:16:22 1998 +++ new/linux/arch/i386/kernel/init_task.c Tue May 11 23:37:40 1999 @@ -10,7 +10,7 @@ static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM; +struct mm_struct init_mm = INIT_MM(init_mm); /* * Initial task structure. @@ -20,5 +20,6 @@ * "init_task" linker map entry.. */ union task_union init_task_union - __attribute__((__section__(".data.init_task"))) = { INIT_TASK }; + __attribute__((__section__(".data.init_task"))) = + { INIT_TASK(init_task_union.task) }; diff -ur --new-file old/linux/arch/i386/kernel/mtrr.c new/linux/arch/i386/kernel/mtrr.c --- old/linux/arch/i386/kernel/mtrr.c Mon May 10 19:32:45 1999 +++ new/linux/arch/i386/kernel/mtrr.c Fri May 14 17:59:54 1999 @@ -1,6 +1,6 @@ /* Generic MTRR (Memory Type Range Register) driver. - Copyright (C) 1997-1998 Richard Gooch + Copyright (C) 1997-1999 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -196,6 +196,11 @@ 19990310 Richard Gooch Support K6-II/III based on Alan Cox's patches. v1.34 + 19990511 Bart Hartgers + Support Centaur C6 MCR's. + 19990512 Richard Gooch + Minor cleanups. + v1.35 */ #include #include @@ -232,7 +237,7 @@ #include #include "irq.h" -#define MTRR_VERSION "1.34 (19990310)" +#define MTRR_VERSION "1.35 (19990512)" #define TRUE 1 #define FALSE 0 @@ -313,8 +318,13 @@ /* Disable interrupts locally */ __save_flags (ctxt->flags); __cli (); - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return; - + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: + return; + /*break;*/ + } /* Save value of CR4 and clear Page Global Enable (bit 7) */ if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) asm volatile ("movl %%cr4, %0\n\t" @@ -352,12 +362,14 @@ { unsigned long tmp; - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: __restore_flags (ctxt->flags); return; + /*break;*/ } - /* Flush caches and TLBs */ asm volatile ("wbinvd" : : : "memory" ); @@ -399,7 +411,9 @@ return (config & 0xff); /*break;*/ case X86_VENDOR_CYRIX: - /* Cyrix have 8 ARRs */ + /* Cyrix have 8 ARRs */ + case X86_VENDOR_CENTAUR: + /* and Centaur has 8 MCR's */ return 8; /*break;*/ case X86_VENDOR_AMD: @@ -422,6 +436,7 @@ /*break;*/ case X86_VENDOR_CYRIX: case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: return 1; /*break;*/ } @@ -450,7 +465,6 @@ /* Clean up mask_lo so it gives the real address mask. */ mask_lo = (mask_lo & 0xfffff000UL); - /* This works correctly if size is a power of two, i.e. a contiguous range. */ *size = ~(mask_lo - 1); @@ -480,7 +494,6 @@ /* Enable interrupts if it was enabled previously */ __restore_flags (flags); - shift = ((unsigned char *) base)[1] & 0x0f; *base &= 0xfffff000UL; @@ -550,6 +563,20 @@ return; } /* End Function amd_get_mtrr */ +static struct +{ + unsigned long high; + unsigned long low; +} centaur_mcr[8]; + +static void centaur_get_mcr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) +{ + *base = centaur_mcr[reg].high & 0xfffff000; + *size = (~(centaur_mcr[reg].low & 0xfffff000))+1; + *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ +} /* End Function centaur_get_mcr */ + static void (*get_mtrr) (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) = NULL; @@ -647,11 +674,10 @@ else /* Set the register to the base (already shifted for us), the type (off by one) and an inverted bitmask of the size - The size is the only odd bit. We are fed say 512K We invert this and we get 111 1111 1111 1011 but if you subtract one and invert you get the desired - 111 1111 1111 1100 mask + 111 1111 1111 1100 mask */ *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1); /* @@ -663,10 +689,36 @@ if (do_safe) set_mtrr_done (&ctxt); } /* End Function amd_set_mtrr_up */ + +static void centaur_set_mcr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, + int do_safe) +{ + struct set_mtrr_context ctxt; + unsigned long low, high; + + if (do_safe) set_mtrr_prepare( &ctxt ); + if (size == 0) + { + /* Disable */ + high = low = 0; + } + else + { + high = base & 0xfffff000; /* base works on 4K pages... */ + low = ((~(size-1))&0xfffff000); + low |= 0x1f; /* only support write-combining... */ + } + centaur_mcr[reg].high = high; + centaur_mcr[reg].low = low; + wrmsr (0x110 + reg, low, high); + if (do_safe) set_mtrr_done( &ctxt ); +} /* End Function centaur_set_mtrr_up */ + static void (*set_mtrr_up) (unsigned int reg, unsigned long base, unsigned long size, mtrr_type type, int do_safe) = NULL; - + #ifdef __SMP__ struct mtrr_var_range @@ -694,23 +746,21 @@ { unsigned int lo, hi; int changed = FALSE; - - rdmsr(MTRRphysBase_MSR(index), lo, hi); + rdmsr(MTRRphysBase_MSR(index), lo, hi); if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); changed = TRUE; } - rdmsr(MTRRphysMask_MSR(index), lo, hi); + rdmsr(MTRRphysMask_MSR(index), lo, hi); if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); + wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); changed = TRUE; } - return changed; } /* End Function set_mtrr_var_range_testing */ @@ -723,7 +773,6 @@ for (i = 0; i < 2; i++) rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); - for (i = 0; i < 8; i++) rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); } /* End Function get_fixed_ranges */ @@ -777,14 +826,13 @@ unsigned long lo, dummy; nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges + vrs = state->var_ranges = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); if (vrs == NULL) nvrs = state->num_var_ranges = 0; for (i = 0; i < nvrs; i++) get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); rdmsr (MTRRdefType_MSR, lo, dummy); @@ -818,7 +866,6 @@ if ( set_fixed_ranges_testing(state->fixed_ranges) ) change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type @@ -831,7 +878,7 @@ return change_mask; } /* End Function set_mtrr_state */ - + static atomic_t undone_count; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; @@ -1025,13 +1072,22 @@ } /* Fall through */ case X86_VENDOR_CYRIX: + case X86_VENDOR_CENTAUR: if ( (base & 0xfff) || (size & 0xfff) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: %lx base: %lx\n", size, base); return -EINVAL; } - if (base + size < 0x100000) + if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) + { + if (type != MTRR_TYPE_WRCOMB) + { + printk ("mtrr: only write-combining is supported\n"); + return -EINVAL; + } + } + else if (base + size < 0x100000) { printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n", base, size); @@ -1050,7 +1106,7 @@ } break; case X86_VENDOR_AMD: - /* Apply the K6 block alignment and size rules + /* Apply the K6 block alignment and size rules In order o Uncached or gathering only o 128K or bigger block @@ -1572,6 +1628,30 @@ if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); } /* End Function cyrix_arr_init */ +__initfunc(static void centaur_mcr_init (void)) +{ + unsigned i; + struct set_mtrr_context ctxt; + + set_mtrr_prepare (&ctxt); + /* Unfortunately, MCR's are read-only, so there is no way to + * find out what the bios might have done. + */ + /* Clear all MCR's. + * This way we are sure that the centaur_mcr array contains the actual + * values. The disadvantage is that any BIOS tweaks are thus undone. + */ + for (i = 0; i < 8; ++i) + { + centaur_mcr[i].high = 0; + centaur_mcr[i].low = 0; + wrmsr (0x110 + i , 0, 0); + } + /* Throw the main write-combining switch... */ + wrmsr (0x120, 0x01f0001f, 0); + set_mtrr_done (&ctxt); +} /* End Function centaur_mcr_init */ + __initfunc(static void mtrr_setup (void)) { printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); @@ -1582,7 +1662,6 @@ set_mtrr_up = intel_set_mtrr_up; break; case X86_VENDOR_CYRIX: - printk ("mtrr: Using Cyrix style ARRs\n"); get_mtrr = cyrix_get_arr; set_mtrr_up = cyrix_set_arr_up; get_free_region = cyrix_get_free_region; @@ -1591,6 +1670,10 @@ get_mtrr = amd_get_mtrr; set_mtrr_up = amd_set_mtrr_up; break; + case X86_VENDOR_CENTAUR: + get_mtrr = centaur_get_mcr; + set_mtrr_up = centaur_set_mcr_up; + break; } } /* End Function mtrr_setup */ @@ -1611,6 +1694,9 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; + case X86_VENDOR_CENTAUR: + centaur_mcr_init (); + break; } } /* End Function mtrr_init_boot_cpu */ @@ -1675,6 +1761,9 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; + case X86_VENDOR_CENTAUR: + centaur_mcr_init (); + break; } # endif /* !__SMP__ */ diff -ur --new-file old/linux/arch/i386/kernel/setup.c new/linux/arch/i386/kernel/setup.c --- old/linux/arch/i386/kernel/setup.c Mon May 10 19:32:45 1999 +++ new/linux/arch/i386/kernel/setup.c Fri May 14 17:59:54 1999 @@ -9,6 +9,9 @@ * Force Cyrix 6x86(MX) and M II processors to report MTRR capability * and fix against Cyrix "coma bug" by * Zoltan Boszormenyi February 1999. + * + * Force Centaur C6 processors to report MTRR capability. + * Bart Hartgers , May 199. */ /* @@ -861,6 +864,8 @@ /* lv|=(1<<6); - may help too if the board can cope */ printk("now 0x%X", lv); wrmsr(0x107, lv, hv); + /* Emulate MTRRs using Centaur's MCR. */ + c->x86_capability |= X86_FEATURE_MTRR; } printk("\n"); } diff -ur --new-file old/linux/arch/i386/lib/checksum.S new/linux/arch/i386/lib/checksum.S --- old/linux/arch/i386/lib/checksum.S Fri Jan 15 23:36:20 1999 +++ new/linux/arch/i386/lib/checksum.S Sun May 16 22:17:22 1999 @@ -117,9 +117,11 @@ #else /* CPU==686 */ csum_partial: - movl 12(%esp),%eax # Function arg: unsigned int sum - movl 8(%esp),%ecx # Function arg: int len - movl 4(%esp),%esi # Function arg: const unsigned char *buf + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: const unsigned char *buf testl $2, %esi jnz 30f @@ -204,6 +206,8 @@ addl %ebx,%eax adcl $0,%eax 80: + popl %ebx + popl %esi ret #endif /* CPU==686 */ @@ -369,7 +373,7 @@ #define ROUND1(x) \ SRC(movl x(%esi), %ebx ) ; \ - addl %ebx, %eax\n ; \ + addl %ebx, %eax ; \ DST(movl %ebx, x(%edi) ) ; #define ROUND(x) \ diff -ur --new-file old/linux/arch/m68k/atari/stdma.c new/linux/arch/m68k/atari/stdma.c --- old/linux/arch/m68k/atari/stdma.c Fri Feb 13 01:30:12 1998 +++ new/linux/arch/m68k/atari/stdma.c Sun May 16 00:05:35 1999 @@ -43,7 +43,7 @@ /* int func to be called */ static void (*stdma_isr)(int, void *, struct pt_regs *) = NULL; static void *stdma_isr_data = NULL; /* data passed to isr */ -static struct wait_queue *stdma_wait = NULL; /* wait queue for ST-DMA */ +static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ diff -ur --new-file old/linux/arch/m68k/mac/adb-bus.c new/linux/arch/m68k/mac/adb-bus.c --- old/linux/arch/m68k/mac/adb-bus.c Mon Oct 5 22:54:39 1998 +++ new/linux/arch/m68k/mac/adb-bus.c Sun May 16 00:05:35 1999 @@ -2328,12 +2328,12 @@ struct adb_request req; }; -static struct wait_queue *adb_wait; +static DECLARE_WAIT_QUEUE_HEAD(adb_wait); static int adb_wait_reply(struct adbdev_state *state, struct file *file) { int ret = 0; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait,current); add_wait_queue(&adb_wait, &wait); current->state = TASK_INTERRUPTIBLE; @@ -2552,12 +2552,12 @@ struct adb_request req; }; -static struct wait_queue *adb_wait; +static DECLARE_WAIT_QUEUE_HEAD(adb_wait); static int adb_wait_reply(struct adbdev_state *state, struct file *file) { int ret = 0; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); #if (ADBDEBUG & ADBDEBUG_DEVICE) printk("ADB request: wait_reply (blocking ... \n"); diff -ur --new-file old/linux/arch/mips/kernel/irixsig.c new/linux/arch/mips/kernel/irixsig.c --- old/linux/arch/mips/kernel/irixsig.c Thu Nov 5 18:58:29 1998 +++ new/linux/arch/mips/kernel/irixsig.c Sun May 16 00:05:35 1999 @@ -666,7 +666,7 @@ int options, struct rusage *ru) { int flag, retval; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait,current); struct task_struct *p; lock_kernel(); diff -ur --new-file old/linux/arch/mips/lib/ide-no.c new/linux/arch/mips/lib/ide-no.c --- old/linux/arch/mips/lib/ide-no.c Tue Oct 20 22:52:54 1998 +++ new/linux/arch/mips/lib/ide-no.c Thu May 13 20:00:08 1999 @@ -11,6 +11,7 @@ */ #include #include +#include #include #include @@ -24,8 +25,10 @@ return 0; } -static void no_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, - int *irq) +static void no_ide_init_hwif_ports ( hw_regs_t *hw, + ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, + int *irq) { } diff -ur --new-file old/linux/arch/mips/lib/ide-std.c new/linux/arch/mips/lib/ide-std.c --- old/linux/arch/mips/lib/ide-std.c Wed Aug 5 01:06:57 1998 +++ new/linux/arch/mips/lib/ide-std.c Thu May 13 20:00:08 1999 @@ -11,6 +11,7 @@ */ #include #include +#include #include static int std_ide_default_irq(ide_ioreg_t base) @@ -41,15 +42,23 @@ } } -static void std_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, - int *irq) +static void std_ide_init_hwif_ports ( hw_regs_t *hw, + ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, + int *irq) { - ide_ioreg_t port = base; - int i = 8; + ide_ioreg_t reg = data_port; + int i; - while (i--) - *p++ = port++; - *p++ = base + 0x206; + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; + } if (irq != NULL) *irq = 0; } diff -ur --new-file old/linux/arch/ppc/8xx_io/uart.c new/linux/arch/ppc/8xx_io/uart.c --- old/linux/arch/ppc/8xx_io/uart.c Wed Dec 23 18:44:40 1998 +++ new/linux/arch/ppc/8xx_io/uart.c Sun May 16 00:05:35 1999 @@ -155,8 +155,8 @@ long pgrp; /* pgrp of opening process */ struct tq_struct tqueue; struct tq_struct tqueue_hangup; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; /* CPM Buffer Descriptor pointers. */ @@ -1733,7 +1733,7 @@ ser_info_t *info) { #ifdef DO_THIS_LATER - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); #endif struct serial_state *state = info->state; int retval; diff -ur --new-file old/linux/arch/ppc/kernel/apus_setup.c new/linux/arch/ppc/kernel/apus_setup.c --- old/linux/arch/ppc/kernel/apus_setup.c Thu Apr 29 21:39:01 1999 +++ new/linux/arch/ppc/kernel/apus_setup.c Thu May 13 20:00:08 1999 @@ -561,9 +561,9 @@ } __initfunc(void -apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)) +apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)) { - m68k_ide_init_hwif_ports(p, base, irq); + m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq); } #endif diff -ur --new-file old/linux/arch/ppc/kernel/chrp_setup.c new/linux/arch/ppc/kernel/chrp_setup.c --- old/linux/arch/ppc/kernel/chrp_setup.c Tue May 11 17:24:32 1999 +++ new/linux/arch/ppc/kernel/chrp_setup.c Thu May 13 20:00:08 1999 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -561,16 +562,23 @@ ppc_generic_ide_fix_driveid(id); } -void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +void +chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { - ide_ioreg_t port = base; - int i = 8; + ide_ioreg_t reg = data_port; + int i; - while (i--) - *p++ = port++; - *p++ = port; - if (irq != NULL) - *irq = chrp_ide_irq; + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = 0; + } + if (irq != NULL) + hw->irq = chrp_ide_irq; } EXPORT_SYMBOL(chrp_ide_irq); diff -ur --new-file old/linux/arch/ppc/kernel/mbx_setup.c new/linux/arch/ppc/kernel/mbx_setup.c --- old/linux/arch/ppc/kernel/mbx_setup.c Thu Apr 29 21:39:01 1999 +++ new/linux/arch/ppc/kernel/mbx_setup.c Thu May 13 20:00:08 1999 @@ -380,23 +380,35 @@ ppc_generic_ide_fix_driveid(id); } -void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) +void +mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { - ide_ioreg_t port = base; - int i = 8; + ide_ioreg_t reg = data_port; + int i; + + *irq = 0; + + if (data_port != 0) /* Only map the first ATA flash drive */ + return; - while (i--) - *p++ = port++; - *p++ = base + 0x206; - if (irq != NULL) - *irq = 0; #ifdef ATA_FLASH - base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200); - for (i = 0; i < 8; ++i) - *p++ = base++; - *p = ++base; /* Does not matter */ + + reg = (ide_ioreg_t) ioremap(PCMCIA_MEM_ADDR, 0x200); + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + + /* Does not matter */ + + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = reg; + } if (irq) - *irq = 13; + hw->irq = 13; #endif } #endif diff -ur --new-file old/linux/arch/ppc/kernel/pmac_setup.c new/linux/arch/ppc/kernel/pmac_setup.c --- old/linux/arch/ppc/kernel/pmac_setup.c Tue May 11 17:24:32 1999 +++ new/linux/arch/ppc/kernel/pmac_setup.c Thu May 13 20:00:08 1999 @@ -365,7 +365,7 @@ #ifdef CONFIG_BLK_DEV_IDE_PMAC extern int pmac_ide_count; extern struct device_node *pmac_ide_node[]; -static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; +static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89 }; __initfunc(kdev_t find_ide_boot(void)) { @@ -544,7 +544,16 @@ } /* This is declared in drivers/block/ide-pmac.c */ -void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq); +void pmac_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq); + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +void +ide_init_default_hwifs(void) +{ +} #endif __initfunc(void diff -ur --new-file old/linux/arch/ppc/kernel/ppc_ksyms.c new/linux/arch/ppc/kernel/ppc_ksyms.c --- old/linux/arch/ppc/kernel/ppc_ksyms.c Thu Apr 29 21:39:01 1999 +++ new/linux/arch/ppc/kernel/ppc_ksyms.c Thu May 13 20:00:08 1999 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff -ur --new-file old/linux/arch/ppc/kernel/prep_setup.c new/linux/arch/ppc/kernel/prep_setup.c --- old/linux/arch/ppc/kernel/prep_setup.c Tue May 11 17:24:32 1999 +++ new/linux/arch/ppc/kernel/prep_setup.c Thu May 13 20:00:08 1999 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -691,14 +692,20 @@ } __initfunc(void -prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)) +prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)) { - ide_ioreg_t port = base; - int i = 8; + ide_ioreg_t reg = data_port; + int i; - while (i--) - *p++ = port++; - *p++ = base + 0x206; + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; + } if (irq != NULL) *irq = 0; } diff -ur --new-file old/linux/arch/ppc/kernel/residual.c new/linux/arch/ppc/kernel/residual.c --- old/linux/arch/ppc/kernel/residual.c Sun Nov 15 19:51:44 1998 +++ new/linux/arch/ppc/kernel/residual.c Thu May 13 20:00:08 1999 @@ -46,6 +46,7 @@ #include #include #include +#include #include diff -ur --new-file old/linux/arch/ppc/kernel/setup.c new/linux/arch/ppc/kernel/setup.c --- old/linux/arch/ppc/kernel/setup.c Thu Apr 29 21:39:01 1999 +++ new/linux/arch/ppc/kernel/setup.c Thu May 13 20:00:08 1999 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -160,10 +161,10 @@ } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +void ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { if (ppc_ide_md.ide_init_hwif != NULL) { - ppc_ide_md.ide_init_hwif(p, base, irq); + ppc_ide_md.ide_init_hwif(hw, data_port, ctrl_port, irq); } } #endif diff -ur --new-file old/linux/arch/sparc/ap1000/util.c new/linux/arch/sparc/ap1000/util.c --- old/linux/arch/sparc/ap1000/util.c Wed Dec 23 18:44:40 1998 +++ new/linux/arch/sparc/ap1000/util.c Wed May 12 17:41:12 1999 @@ -355,7 +355,7 @@ } -static struct wait_queue *timer_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(timer_wait); static void wait_callback(unsigned long _ignored) { diff -ur --new-file old/linux/arch/sparc/defconfig new/linux/arch/sparc/defconfig --- old/linux/arch/sparc/defconfig Fri Apr 23 04:24:51 1999 +++ new/linux/arch/sparc/defconfig Sat May 15 20:12:09 1999 @@ -229,6 +229,7 @@ CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +CONFIG_EFS_FS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m diff -ur --new-file old/linux/arch/sparc/kernel/init_task.c new/linux/arch/sparc/kernel/init_task.c --- old/linux/arch/sparc/kernel/init_task.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/init_task.c Wed May 12 17:41:12 1999 @@ -9,11 +9,13 @@ static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM; +struct mm_struct init_mm = INIT_MM(init_mm); /* .text section in head.S is aligned at 8k boundry and this gets linked * right after that so that the init_task_union is aligned properly as well. * If this is not aligned on a 8k boundry, then you should change code * in etrap.S which assumes it. */ -union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; +union task_union init_task_union + __attribute__((__section__(".text"))) = + { INIT_TASK(init_task_union.task) }; diff -ur --new-file old/linux/arch/sparc/mm/asyncd.c new/linux/arch/sparc/mm/asyncd.c --- old/linux/arch/sparc/mm/asyncd.c Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/mm/asyncd.c Wed May 12 17:41:12 1999 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.12 1998/09/13 04:30:30 davem Exp $ +/* $Id: asyncd.c,v 1.13 1999/05/12 11:11:34 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -39,7 +39,7 @@ /* * The wait queue for waking up the async daemon: */ -static struct wait_queue * asyncd_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait); struct async_job { volatile struct async_job *next; diff -ur --new-file old/linux/arch/sparc64/defconfig new/linux/arch/sparc64/defconfig --- old/linux/arch/sparc64/defconfig Fri Apr 23 04:24:51 1999 +++ new/linux/arch/sparc64/defconfig Sat May 15 20:12:09 1999 @@ -267,6 +267,7 @@ CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +CONFIG_EFS_FS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m diff -ur --new-file old/linux/arch/sparc64/kernel/init_task.c new/linux/arch/sparc64/kernel/init_task.c --- old/linux/arch/sparc64/kernel/init_task.c Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc64/kernel/init_task.c Wed May 12 17:41:12 1999 @@ -9,11 +9,13 @@ static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM; +struct mm_struct init_mm = INIT_MM(init_mm); /* .text section in head.S is aligned at 2 page boundry and this gets linked * right after that so that the init_task_union is aligned properly as well. * We really don't need this special alignment like the Intel does, but * I do it anyways for completeness. */ -union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; +union task_union init_task_union + __attribute__((__section__(".text"))) = + { INIT_TASK(init_task_union.task) }; diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sparc32.c new/linux/arch/sparc64/kernel/sys_sparc32.c --- old/linux/arch/sparc64/kernel/sys_sparc32.c Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/kernel/sys_sparc32.c Sun May 16 19:39:51 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $ +/* $Id: sys_sparc32.c,v 1.108 1999/05/16 10:50:32 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2363,6 +2363,94 @@ __scm_destroy(scm); } +/* In these cases we (currently) can just copy to data over verbatim + * because all CMSGs created by the kernel have well defined types which + * have the same layout in both the 32-bit and 64-bit API. One must add + * some special cased conversions here if we start sending control messages + * with incompatible types. + * + * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after + * we do our work. The remaining cases are: + * + * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean + * IP_TTL int 32-bit clean + * IP_TOS __u8 32-bit clean + * IP_RECVOPTS variable length 32-bit clean + * IP_RETOPTS variable length 32-bit clean + * (these last two are clean because the types are defined + * by the IPv4 protocol) + * IP_RECVERR struct sock_extended_err + + * struct sockaddr_in 32-bit clean + * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + + * struct sockaddr_in6 32-bit clean + * IPV6_PKTINFO struct in6_pktinfo 32-bit clean + * IPV6_HOPLIMIT int 32-bit clean + * IPV6_FLOWINFO u32 32-bit clean + * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean + * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean + * IPV6_RTHDR ipv6 routing exthdr 32-bit clean + * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean + */ +static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) +{ + unsigned char *workbuf, *wp; + unsigned long bufsz, space_avail; + struct cmsghdr *ucmsg; + + bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf = kmalloc(bufsz, GFP_KERNEL); + if(workbuf == NULL) + goto fail; + + /* To make this more sane we assume the kernel sends back properly + * formatted control messages. Because of how the kernel will truncate + * the cmsg_len for MSG_TRUNC cases, we need not check that case either. + */ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; + while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; + int clen64, clen32; + + /* UCMSG is the 64-bit format CMSG entry in user-space. + * KCMSG32 is within the kernel space temporary buffer + * we use to convert into a 32-bit style CMSG. + */ + __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); + __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); + __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); + + clen64 = kcmsg32->cmsg_len; + copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), + clen64 - CMSG_ALIGN(sizeof(*ucmsg))); + clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + + CMSG32_ALIGN(sizeof(struct cmsghdr32))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + } + + /* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); + copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); + + kmsg->msg_control = (struct cmsghdr *) + (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; + + kfree(workbuf); + return; + +fail: + /* If we leave the 64-bit format CMSG chunks in there, + * the application could get confused and crash. So to + * ensure greater recovery, we report no CMSGs. + */ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} + asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) { struct socket *sock; @@ -2455,6 +2543,14 @@ if(scm.fp) __scm_destroy(&scm); } else { + /* If recvmsg processing itself placed some + * control messages into user space, it's is + * using 64-bit CMSG processing, so we need + * to fix it up before we tack on more stuff. + */ + if((unsigned long) kern_msg.msg_control != cmsg_ptr) + cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr); + /* Wheee... */ if(sock->passcred) put_cmsg32(&kern_msg, @@ -2471,9 +2567,9 @@ if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(cmsg_ptr != 0 && err >= 0) { - u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control); - err = __put_user(ucmsg_ptr, &user_msg->msg_control); - err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen); + unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); + __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr); + err |= __put_user(uclen, &user_msg->msg_controllen); } if(err >= 0) err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); diff -ur --new-file old/linux/arch/sparc64/mm/asyncd.c new/linux/arch/sparc64/mm/asyncd.c --- old/linux/arch/sparc64/mm/asyncd.c Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc64/mm/asyncd.c Wed May 12 17:41:12 1999 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.5 1998/09/13 04:30:33 davem Exp $ +/* $Id: asyncd.c,v 1.6 1999/05/12 11:11:48 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -39,7 +39,7 @@ /* * The wait queue for waking up the async daemon: */ -static struct wait_queue * asyncd_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait); struct async_job { volatile struct async_job *next; diff -ur --new-file old/linux/arch/sparc64/solaris/fs.c new/linux/arch/sparc64/solaris/fs.c --- old/linux/arch/sparc64/solaris/fs.c Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/solaris/fs.c Sat May 15 20:12:09 1999 @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.12 1999/01/02 16:46:06 davem Exp $ +/* $Id: fs.c,v 1.13 1999/05/14 07:24:37 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -410,7 +410,11 @@ mm_segment_t old_fs = get_fs(); int error; struct sol_statvfs *ss = (struct sol_statvfs *)A(buf); - + + if (!inode->i_sb) + return -ENODEV; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; set_fs (KERNEL_DS); error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); set_fs (old_fs); @@ -448,6 +452,10 @@ int error; struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf); + if (!inode->i_sb) + return -ENODEV; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; set_fs (KERNEL_DS); error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); set_fs (old_fs); @@ -489,9 +497,7 @@ if (!IS_ERR(dentry)) { struct inode * inode = dentry->d_inode; - error = -ENOSYS; - if (inode->i_sb->s_op->statfs) - error = report_statvfs(inode, buf); + error = report_statvfs(inode, buf); dput(dentry); } unlock_kernel(); @@ -515,10 +521,6 @@ error = -ENOENT; else if (!(inode = dentry->d_inode)) error = -ENOENT; - else if (!inode->i_sb) - error = -ENODEV; - else if (!inode->i_sb->s_op->statfs) - error = -ENOSYS; else error = report_statvfs(inode, buf); fput(file); @@ -538,9 +540,7 @@ if (!IS_ERR(dentry)) { struct inode * inode = dentry->d_inode; - error = -ENOSYS; - if (inode->i_sb->s_op->statfs) - error = report_statvfs64(inode, buf); + error = report_statvfs64(inode, buf); dput(dentry); } unlock_kernel(); @@ -564,10 +564,6 @@ error = -ENOENT; else if (!(inode = dentry->d_inode)) error = -ENOENT; - else if (!inode->i_sb) - error = -ENODEV; - else if (!inode->i_sb->s_op->statfs) - error = -ENOSYS; else error = report_statvfs64(inode, buf); fput(file); diff -ur --new-file old/linux/arch/sparc64/solaris/ipc.c new/linux/arch/sparc64/solaris/ipc.c --- old/linux/arch/sparc64/solaris/ipc.c Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/solaris/ipc.c Sat May 15 20:12:09 1999 @@ -1,4 +1,4 @@ -/* $Id: ipc.c,v 1.3 1998/07/30 11:29:47 davem Exp $ +/* $Id: ipc.c,v 1.4 1999/05/13 07:11:37 jj Exp $ * ipc.c: Solaris IPC emulation * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff -ur --new-file old/linux/arch/sparc64/solaris/timod.c new/linux/arch/sparc64/solaris/timod.c --- old/linux/arch/sparc64/solaris/timod.c Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/solaris/timod.c Wed May 12 17:41:12 1999 @@ -1,4 +1,4 @@ -/* $Id: timod.c,v 1.1 1998/03/26 08:46:18 jj Exp $ +/* $Id: timod.c,v 1.2 1999/05/12 11:11:55 davem Exp $ * timod.c: timod emulation. * * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) @@ -76,7 +76,7 @@ #define BUF_SIZE PAGE_SIZE #define PUT_MAGIC(a,m) -#define CHECK_MAGIC(a,m) +#define SCHECK_MAGIC(a,m) #define BUF_OFFSET 0 #define MKCTL_TRAILER 0 @@ -86,7 +86,7 @@ #define BUFPAGE_MAGIC 0xBADC0DEDDEADBABEL #define MKCTL_MAGIC 0xDEADBABEBADC0DEDL #define PUT_MAGIC(a,m) do{(*(u64*)(a))=(m);}while(0) -#define CHECK_MAGIC(a,m) do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\ +#define SCHECK_MAGIC(a,m) do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\ __FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0) #define BUF_OFFSET sizeof(u64) #define MKCTL_TRAILER sizeof(u64) @@ -117,8 +117,8 @@ { SOLD("putting page"); p = p - BUF_OFFSET; - CHECK_MAGIC(p,BUFPAGE_MAGIC); - CHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC); + SCHECK_MAGIC(p,BUFPAGE_MAGIC); + SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC); spin_lock(&timod_pagelock); if (page) { spin_unlock(&timod_pagelock); @@ -721,7 +721,7 @@ #define min(a,b) ((a)<(b)?(a):(b)) #endif int l = min(ctl_maxlen, it->length); - CHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC); + SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC); SOLD("purting ctl data"); if(copy_to_user(ctl_buf, (char*)&it->type + sock->offset, l)) diff -ur --new-file old/linux/drivers/acorn/block/fd1772.c new/linux/drivers/acorn/block/fd1772.c --- old/linux/drivers/acorn/block/fd1772.c Thu Jan 7 17:46:58 1999 +++ new/linux/drivers/acorn/block/fd1772.c Sun May 16 00:05:35 1999 @@ -267,7 +267,7 @@ /* Synchronization of FDC1772 access. */ static volatile int fdc_busy = 0; -static struct wait_queue *fdc_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static unsigned int changed_floppies = 0xff, fake_change = 0; diff -ur --new-file old/linux/drivers/acorn/block/mfmhd.c new/linux/drivers/acorn/block/mfmhd.c --- old/linux/drivers/acorn/block/mfmhd.c Mon Aug 24 22:14:09 1998 +++ new/linux/drivers/acorn/block/mfmhd.c Sun May 16 00:05:35 1999 @@ -195,7 +195,7 @@ static int mfm_sizes[MFM_MAXDRIVES << 6]; static int mfm_blocksizes[MFM_MAXDRIVES << 6]; static int mfm_sectsizes[MFM_MAXDRIVES << 6]; -static struct wait_queue *mfm_wait_open = NULL; +static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open); /* Stuff from the assembly routines */ extern unsigned int hdc63463_baseaddress; /* Controller base address */ diff -ur --new-file old/linux/drivers/ap1000/ap.c new/linux/drivers/ap1000/ap.c --- old/linux/drivers/ap1000/ap.c Mon Aug 24 22:45:51 1998 +++ new/linux/drivers/ap1000/ap.c Sun May 16 00:05:35 1999 @@ -36,7 +36,7 @@ #define NUM_APDEVS 8 #define MAX_REQUESTS 1 -static struct wait_queue * busy_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int ap_blocksizes[NUM_APDEVS]; static int ap_length[NUM_APDEVS]; diff -ur --new-file old/linux/drivers/ap1000/ddv.c new/linux/drivers/ap1000/ddv.c --- old/linux/drivers/ap1000/ddv.c Mon Aug 24 22:02:44 1998 +++ new/linux/drivers/ap1000/ddv.c Sun May 16 00:05:35 1999 @@ -84,7 +84,7 @@ static char *ddv_opcodep = NULL; static struct request *next_request = NULL; -static struct wait_queue * busy_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */ int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */ @@ -93,7 +93,7 @@ /* these are used by the ddv_daemon, which services remote disk requests */ static struct remote_request *rem_queue = NULL; static struct remote_request *rem_queue_end; -static struct wait_queue *ddv_daemon_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait); static int opiu_kernel_loaded = 0; diff -ur --new-file old/linux/drivers/atm/ambassador.c new/linux/drivers/atm/ambassador.c --- old/linux/drivers/atm/ambassador.c Thu Jun 3 04:26:57 1999 +++ new/linux/drivers/atm/ambassador.c Thu Jun 3 04:28:25 1999 @@ -880,7 +880,9 @@ while (irq_ok_old != irq_ok && irq_ok < 100) { unsigned char pool; +#ifdef DEBUG_AMBASSADOR u32 ints = rd_mem (dev, &mem->interrupt); +#endif wr_mem (dev, &mem->interrupt, -1); PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u", ints, irq_ok); irq_ok_old = irq_ok; @@ -912,6 +914,7 @@ /********** don't panic... yeah, right **********/ +#ifdef DEBUG_AMBASSADOR static void dont_panic (amb_dev * dev) { amb_cq * cq = &dev->cq; amb_txq * txq; @@ -962,13 +965,14 @@ restore_flags (flags); return; } +#endif /********** make rate (not quite as much fun as Horizon) **********/ static unsigned int make_rate (unsigned int rate, rounding r, u16 * bits, unsigned int * actual) { - unsigned char exp; - unsigned int man; + unsigned char exp = 0; /* silence gcc */ + unsigned int man = 0; PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate); @@ -1060,8 +1064,6 @@ switch (r) { case round_up: { - exp = 0; - man = 0; break; } case round_down: { @@ -1069,8 +1071,6 @@ break; } case round_nearest: { - exp = 0; - man = 0; break; } } @@ -1104,8 +1104,8 @@ struct atm_trafprm * txtp; struct atm_trafprm * rxtp; u16 tx_rate_bits; - u16 tx_vc_bits; - u16 tx_frame_bits; + u16 tx_vc_bits = 0; /* silence gcc */ + u16 tx_frame_bits = 0; // int pcr; amb_dev * dev = AMB_DEV(atm_vcc->dev); @@ -1865,7 +1865,8 @@ [adap_run_in_iram] = 1, [adap_end_download] = 1 }; - + +#if 0 /* unused */ unsigned int command_successes [] = { [host_memory_test] = COMMAND_PASSED_TEST, [read_adapter_memory] = COMMAND_READ_DATA_OK, @@ -1879,6 +1880,7 @@ [adap_run_in_iram] = COMMAND_COMPLETE, [adap_end_download] = COMMAND_COMPLETE }; +#endif int decode_loader_error (u32 result) { int res; @@ -2188,7 +2190,7 @@ unsigned char pool; unsigned long timeout; - inline u32 x (void * addr) { + static inline u32 x (void * addr) { return cpu_to_be32 (virt_to_bus (addr)); } @@ -2380,7 +2382,7 @@ // semaphore for txer/rxer modifications - we cannot use a // spinlock as the critical region needs to process switches - dev->vcc_sf = MUTEX; + init_MUTEX(&dev->vcc_sf); // queue manipulation spinlocks; we want atomic reads and // writes to the queue descriptors (handles IRQ and SMP) // consider replacing "int pending" -> "atomic_t available" diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c --- old/linux/drivers/atm/eni.c Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/eni.c Thu Jun 3 04:28:25 1999 @@ -900,7 +900,7 @@ memset(eni_dev->rx_map,0,PAGE_SIZE); eni_dev->fast = eni_dev->last_fast = NULL; eni_dev->slow = eni_dev->last_slow = NULL; - eni_dev->rx_wait = NULL; + init_waitqueue_head(&eni_dev->rx_wait); skb_queue_head_init(&eni_dev->rx_queue); eni_dev->serv_read = eni_in(MID_SERV_WRITE); eni_out(0,MID_DMA_WR_RX); @@ -1403,7 +1403,7 @@ eni_dev = ENI_DEV(dev); eni_dev->lost = 0; eni_dev->tx_bw = ATM_OC3_PCR; - eni_dev->tx_wait = NULL; + init_waitqueue_head(&eni_dev->tx_wait); eni_dev->ubr = NULL; skb_queue_head_init(&eni_dev->tx_queue); eni_out(0,MID_DMA_WR_TX); diff -ur --new-file old/linux/drivers/atm/eni.h new/linux/drivers/atm/eni.h --- old/linux/drivers/atm/eni.h Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/eni.h Thu Jun 3 04:28:25 1999 @@ -72,7 +72,7 @@ struct eni_tx tx[NR_CHAN]; /* TX channels */ struct eni_tx *ubr; /* UBR channel */ struct sk_buff_head tx_queue; /* PDUs currently being TX DMAed*/ - struct wait_queue *tx_wait; /* for close */ + wait_queue_head_t tx_wait; /* for close */ int tx_bw; /* remaining bandwidth */ u32 dma[TX_DMA_BUF*2]; /* DMA request scratch area */ /*-------------------------------- RX part */ @@ -81,7 +81,7 @@ struct atm_vcc *slow,*last_slow; struct atm_vcc **rx_map; /* for fast lookups */ struct sk_buff_head rx_queue; /* PDUs currently being RX-DMAed */ - struct wait_queue *rx_wait; /* for close */ + wait_queue_head_t rx_wait; /* for close */ /*-------------------------------- statistics */ unsigned long lost; /* number of lost cells (RX) */ /*-------------------------------- memory management */ diff -ur --new-file old/linux/drivers/atm/horizon.c new/linux/drivers/atm/horizon.c --- old/linux/drivers/atm/horizon.c Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/horizon.c Thu Jun 3 04:28:25 1999 @@ -1824,12 +1824,16 @@ /********** shutdown a card **********/ +#ifdef MODULE + static void hrz_shutdown (const hrz_dev * dev) { hrz_reset_card (dev); GREEN_LED_OFF(dev); } +#endif + /********** read the burnt in address **********/ static u16 __init read_bia (const hrz_dev * dev, u16 addr) { @@ -2631,7 +2635,6 @@ static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, void *optval, int optlen) { - hrz_dev * dev = HRZ_DEV(atm_vcc->dev); PRINTD (DBG_FLOW|DBG_VCC, "hrz_getsockopt"); switch (level) { case SOL_SOCKET: @@ -2653,7 +2656,6 @@ static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, void *optval, int optlen) { - hrz_dev * dev = HRZ_DEV(atm_vcc->dev); PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt"); switch (level) { case SOL_SOCKET: @@ -2906,7 +2908,7 @@ // writes to adapter memory (handles IRQ and SMP) spin_lock_init (&dev->mem_lock); - dev->tx_queue = 0; + init_waitqueue_head(&dev->tx_queue); // vpi in 0..4, vci in 6..10 dev->atm_dev->ci_range.vpi_bits = vpi_bits; diff -ur --new-file old/linux/drivers/atm/horizon.h new/linux/drivers/atm/horizon.h --- old/linux/drivers/atm/horizon.h Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/horizon.h Thu Jun 3 04:28:25 1999 @@ -421,7 +421,7 @@ unsigned int tx_regions; // number of remaining regions spinlock_t mem_lock; - struct wait_queue * tx_queue; + wait_queue_head_t tx_queue; u8 irq; u8 flags; diff -ur --new-file old/linux/drivers/atm/nicstar.c new/linux/drivers/atm/nicstar.c --- old/linux/drivers/atm/nicstar.c Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/nicstar.c Thu Jun 3 04:28:25 1999 @@ -991,7 +991,7 @@ scq->scd = scd; scq->num_entries = size / NS_SCQE_SIZE; scq->tbd_count = 0; - scq->scqfull_waitq = NULL; + init_waitqueue_head(&scq->scqfull_waitq); scq->full = 0; for (i = 0; i < scq->num_entries; i++) diff -ur --new-file old/linux/drivers/atm/nicstar.h new/linux/drivers/atm/nicstar.h --- old/linux/drivers/atm/nicstar.h Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/nicstar.h Thu Jun 3 04:28:25 1999 @@ -680,7 +680,7 @@ u32 scd; /* SRAM address of the corresponding SCD */ int tbd_count; /* Only meaningful on variable rate */ - struct wait_queue *scqfull_waitq; + wait_queue_head_t scqfull_waitq; volatile char full; /* SCQ full indicator */ } scq_info; diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c --- old/linux/drivers/atm/zatm.c Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/zatm.c Thu Jun 3 04:28:25 1999 @@ -1146,7 +1146,7 @@ } zatm_vcc->tx_chan = chan; skb_queue_head_init(&zatm_vcc->tx_queue); - zatm_vcc->tx_wait = NULL; + init_waitqueue_head(&zatm_vcc->tx_wait); /* initialize ring */ zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL); if (!zatm_vcc->ring) return -ENOMEM; diff -ur --new-file old/linux/drivers/atm/zatm.h new/linux/drivers/atm/zatm.h --- old/linux/drivers/atm/zatm.h Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/atm/zatm.h Thu Jun 3 04:28:25 1999 @@ -72,7 +72,7 @@ int tx_chan; /* TX channel, 0 if none */ int shaper; /* shaper, <0 if none */ struct sk_buff_head tx_queue; /* list of buffers in transit */ - struct wait_queue *tx_wait; /* for close */ + wait_queue_head_t tx_wait; /* for close */ u32 *ring; /* transmit ring */ int ring_curr; /* current write position */ int txing; /* number of transmits in progress */ diff -ur --new-file old/linux/drivers/block/Config.in new/linux/drivers/block/Config.in --- old/linux/drivers/block/Config.in Thu Apr 29 21:53:48 1999 +++ new/linux/drivers/block/Config.in Thu May 13 20:00:08 1999 @@ -19,7 +19,13 @@ else bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE + if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then + bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE + fi dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE + if [ "$CONFIG_BLK_DEV_IDECD" = "y" ]; then + bool ' Include CD-Changer Reporting' CONFIG_IDECD_SLOTS + fi 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 @@ -34,16 +40,29 @@ if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD + bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then bool ' Use DMA by default when available' CONFIG_IDEDMA_AUTO fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 + bool ' Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 + bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 + bool ' PDC20246 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20246 + bool ' PDC20262 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20262 + if [ "$CONFIG_BLK_DEV_PDC20246" = "y" -o \ + "$CONFIG_BLK_DEV_PDC20262" = "y" ]; then + define_bool CONFIG_BLK_DEV_PDC202XX y + else + define_bool CONFIG_BLK_DEV_PDC202XX n + fi + bool ' HPT343 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT343 fi fi fi @@ -72,10 +91,25 @@ bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then - bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 - fi + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + fi fi fi + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE + fi + fi + if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA + fi + if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE + fi + if [ "$CONFIG_MAC" = "y" ]; then + bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE + fi fi fi if [ "$CONFIG_MCA" = "y" ]; then @@ -127,6 +161,19 @@ dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then source drivers/block/paride/Config.in +fi + + +if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ + "$CONFIG_IDE_CHIPSETS" = "y" -o \ + "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ + "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ + "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ + "$CONFIG_BLK_DEV_HPT343" = "y" -o \ + "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + define_bool CONFIG_BLK_DEV_IDE_MODES y +else + define_bool CONFIG_BLK_DEV_IDE_MODES n fi if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then diff -ur --new-file old/linux/drivers/block/MAKEDEV-IDE45 new/linux/drivers/block/MAKEDEV-IDE45 --- old/linux/drivers/block/MAKEDEV-IDE45 Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/MAKEDEV-IDE45 Thu May 13 20:00:08 1999 @@ -0,0 +1,99 @@ +#!/bin/sh +# +# Andre Hedrick +# +# The song goes, "I did it the hard way..........." +# + +if [ ! -f /dev/hdi ]; then \ + echo "Making IDE4 Primary Devices hdi's"; \ + mknod /dev/hdi b 56 0; \ + mknod /dev/hdi1 b 56 1; \ + mknod /dev/hdi2 b 56 2; \ + mknod /dev/hdi3 b 56 3; \ + mknod /dev/hdi4 b 56 4; \ + mknod /dev/hdi5 b 56 5; \ + mknod /dev/hdi6 b 56 6; \ + mknod /dev/hdi7 b 56 7; \ + mknod /dev/hdi8 b 56 8; \ + mknod /dev/hdi9 b 56 9; \ + mknod /dev/hdi10 b 56 10; \ + mknod /dev/hdi11 b 56 11; \ + mknod /dev/hdi12 b 56 12; \ + mknod /dev/hdi13 b 56 13; \ + mknod /dev/hdi14 b 56 14; \ + mknod /dev/hdi15 b 56 15; \ + mknod /dev/hdi16 b 56 16; \ + chown root.disk /dev/hdi*; \ + chmod 660 /dev/hdi*; \ +fi + +if [ ! -f /dev/hdj ]; then \ + echo "Making IDE4 Secondary Devices hdj's"; \ + mknod /dev/hdj b 56 64; \ + mknod /dev/hdj1 b 56 65; \ + mknod /dev/hdj2 b 56 66; \ + mknod /dev/hdj3 b 56 67; \ + mknod /dev/hdj4 b 56 68; \ + mknod /dev/hdj5 b 56 69; \ + mknod /dev/hdj6 b 56 70; \ + mknod /dev/hdj7 b 56 71; \ + mknod /dev/hdj8 b 56 72; \ + mknod /dev/hdj9 b 56 73; \ + mknod /dev/hdj10 b 56 74; \ + mknod /dev/hdj11 b 56 75; \ + mknod /dev/hdj12 b 56 76; \ + mknod /dev/hdj13 b 56 77; \ + mknod /dev/hdj14 b 56 78; \ + mknod /dev/hdj15 b 56 79; \ + mknod /dev/hdj16 b 56 80; \ + chown root.disk /dev/hdj*; \ + chmod 660 /dev/hdj*; \ +fi + +if [ ! -f /dev/hdk ]; then \ + echo "Making IDE5 Primary Devices hdk's"; \ + mknod /dev/hdk b 57 0; \ + mknod /dev/hdk1 b 57 1; \ + mknod /dev/hdk2 b 57 2; \ + mknod /dev/hdk3 b 57 3; \ + mknod /dev/hdk4 b 57 4; \ + mknod /dev/hdk5 b 57 5; \ + mknod /dev/hdk6 b 57 6; \ + mknod /dev/hdk7 b 57 7; \ + mknod /dev/hdk8 b 57 8; \ + mknod /dev/hdk9 b 57 9; \ + mknod /dev/hdk10 b 57 10; \ + mknod /dev/hdk11 b 57 11; \ + mknod /dev/hdk12 b 57 12; \ + mknod /dev/hdk13 b 57 13; \ + mknod /dev/hdk14 b 57 14; \ + mknod /dev/hdk15 b 57 15; \ + mknod /dev/hdk16 b 57 16; \ + chown root.disk /dev/hdk*; \ + chmod 660 /dev/hdk*; \ +fi + +if [ ! -f /dev/hdl ]; then \ + echo "Making IDE5 Secondary Devices hdl's"; \ + mknod /dev/hdl b 57 64; \ + mknod /dev/hdl1 b 57 65; \ + mknod /dev/hdl2 b 57 66; \ + mknod /dev/hdl3 b 57 67; \ + mknod /dev/hdl4 b 57 68; \ + mknod /dev/hdl5 b 57 69; \ + mknod /dev/hdl6 b 57 70; \ + mknod /dev/hdl7 b 57 71; \ + mknod /dev/hdl8 b 57 72; \ + mknod /dev/hdl9 b 57 73; \ + mknod /dev/hdl10 b 57 74; \ + mknod /dev/hdl11 b 57 75; \ + mknod /dev/hdl12 b 57 76; \ + mknod /dev/hdl13 b 57 77; \ + mknod /dev/hdl14 b 57 78; \ + mknod /dev/hdl15 b 57 79; \ + mknod /dev/hdl16 b 57 80; \ + chown root.disk /dev/hdl*; \ + chmod 660 /dev/hdl*; \ +fi + diff -ur --new-file old/linux/drivers/block/MAKEDEV-IDE67 new/linux/drivers/block/MAKEDEV-IDE67 --- old/linux/drivers/block/MAKEDEV-IDE67 Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/MAKEDEV-IDE67 Thu May 13 20:00:08 1999 @@ -0,0 +1,99 @@ +#!/bin/sh +# +# Andre Hedrick +# +# The song goes, "I did it the hard way..........." +# + +if [ ! -f /dev/hdm ]; then \ + echo "Making IDE6 Primary Devices hdm's"; \ + mknod /dev/hdm b 88 0; \ + mknod /dev/hdm1 b 88 1; \ + mknod /dev/hdm2 b 88 2; \ + mknod /dev/hdm3 b 88 3; \ + mknod /dev/hdm4 b 88 4; \ + mknod /dev/hdm5 b 88 5; \ + mknod /dev/hdm6 b 88 6; \ + mknod /dev/hdm7 b 88 7; \ + mknod /dev/hdm8 b 88 8; \ + mknod /dev/hdm9 b 88 9; \ + mknod /dev/hdm10 b 88 10; \ + mknod /dev/hdm11 b 88 11; \ + mknod /dev/hdm12 b 88 12; \ + mknod /dev/hdm13 b 88 13; \ + mknod /dev/hdm14 b 88 14; \ + mknod /dev/hdm15 b 88 15; \ + mknod /dev/hdm16 b 88 16; \ + chown root.disk /dev/hdm*; \ + chmod 660 /dev/hdm*; \ +fi + +if [ ! -f /dev/hdn ]; then \ + echo "Making IDE6 Secondary Devices hdn's"; \ + mknod /dev/hdn b 88 64; \ + mknod /dev/hdn1 b 88 65; \ + mknod /dev/hdn2 b 88 66; \ + mknod /dev/hdn3 b 88 67; \ + mknod /dev/hdn4 b 88 68; \ + mknod /dev/hdn5 b 88 69; \ + mknod /dev/hdn6 b 88 70; \ + mknod /dev/hdn7 b 88 71; \ + mknod /dev/hdn8 b 88 72; \ + mknod /dev/hdn9 b 88 73; \ + mknod /dev/hdn10 b 88 74; \ + mknod /dev/hdn11 b 88 75; \ + mknod /dev/hdn12 b 88 76; \ + mknod /dev/hdn13 b 88 77; \ + mknod /dev/hdn14 b 88 78; \ + mknod /dev/hdn15 b 88 79; \ + mknod /dev/hdn16 b 88 80; \ + chown root.disk /dev/hdn*; \ + chmod 660 /dev/hdn*; \ +fi + +if [ ! -f /dev/hdo ]; then \ + echo "Making IDE7 Primary Devices hdo's"; \ + mknod /dev/hdo b 89 0; \ + mknod /dev/hdo1 b 89 1; \ + mknod /dev/hdo2 b 89 2; \ + mknod /dev/hdo3 b 89 3; \ + mknod /dev/hdo4 b 89 4; \ + mknod /dev/hdo5 b 89 5; \ + mknod /dev/hdo6 b 89 6; \ + mknod /dev/hdo7 b 89 7; \ + mknod /dev/hdo8 b 89 8; \ + mknod /dev/hdo9 b 89 9; \ + mknod /dev/hdo10 b 89 10; \ + mknod /dev/hdo11 b 89 11; \ + mknod /dev/hdo12 b 89 12; \ + mknod /dev/hdo13 b 89 13; \ + mknod /dev/hdo14 b 89 14; \ + mknod /dev/hdo15 b 89 15; \ + mknod /dev/hdo16 b 89 16; \ + chown root.disk /dev/hdo*; \ + chmod 660 /dev/hdo*; \ +fi + +if [ ! -f /dev/hdp ]; then \ + echo "Making IDE7 Secondary Devices hdp's"; \ + mknod /dev/hdp b 89 64; \ + mknod /dev/hdp1 b 89 65; \ + mknod /dev/hdp2 b 89 66; \ + mknod /dev/hdp3 b 89 67; \ + mknod /dev/hdp4 b 89 68; \ + mknod /dev/hdp5 b 89 69; \ + mknod /dev/hdp6 b 89 70; \ + mknod /dev/hdp7 b 89 71; \ + mknod /dev/hdp8 b 89 72; \ + mknod /dev/hdp9 b 89 73; \ + mknod /dev/hdp10 b 89 74; \ + mknod /dev/hdp11 b 89 75; \ + mknod /dev/hdp12 b 89 76; \ + mknod /dev/hdp13 b 89 77; \ + mknod /dev/hdp14 b 89 78; \ + mknod /dev/hdp15 b 89 79; \ + mknod /dev/hdp16 b 89 80; \ + chown root.disk /dev/hdp*; \ + chmod 660 /dev/hdp*; \ +fi + diff -ur --new-file old/linux/drivers/block/Makefile new/linux/drivers/block/Makefile --- old/linux/drivers/block/Makefile Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/block/Makefile Sun May 16 08:43:04 1999 @@ -20,7 +20,7 @@ L_TARGET := block.a -L_OBJS := genhd.o +L_OBJS := genhd.o blkpg.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES LX_OBJS := ll_rw_blk.o @@ -158,12 +158,52 @@ IDE_OBJS += via82c586.o endif +ifeq ($(CONFIG_BLK_DEV_GAYLE),y) +IDE_OBJS += gayle.o +endif + +ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y) +IDE_OBJS += falconide.o +endif + +ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y) +IDE_OBJS += macide.o +endif + +ifeq ($(CONFIG_BLK_DEV_BUDDHA),y) +IDE_OBJS += buddha.o +endif + ifeq ($(CONFIG_BLK_DEV_CMD646),y) IDE_OBJS += cmd646.o endif ifeq ($(CONFIG_BLK_DEV_SL82C105),y) IDE_OBJS += sl82c105.o +endif + +ifeq ($(CONFIG_BLK_DEV_ALI15X3),y) +IDE_OBJS += alim15x3.o +endif + +ifeq ($(CONFIG_BLK_DEV_CY82C693),y) +IDE_OBJS += cy82c693.o +endif + +ifeq ($(CONFIG_BLK_DEV_PIIX),y) +IDE_OBJS += piix.o +endif + +ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) +IDE_OBJS += pdc202xx.o +endif + +ifeq ($(CONFIG_BLK_DEV_AEC6210),y) +IDE_OBJS += aec6210.o +endif + +ifeq ($(CONFIG_BLK_DEV_HPT343),y) +IDE_OBJS += hpt343.o endif ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored diff -ur --new-file old/linux/drivers/block/acsi.c new/linux/drivers/block/acsi.c --- old/linux/drivers/block/acsi.c Tue Dec 29 20:23:59 1998 +++ new/linux/drivers/block/acsi.c Sun May 16 08:43:04 1999 @@ -64,6 +64,7 @@ typedef void Scsi_Device; /* hack to avoid including scsi.h */ #include #include /* for HDIO_GETGEO */ +#include #include #include @@ -245,7 +246,7 @@ static struct hd_struct acsi_part[MAX_DEV<<4] = { {0,0}, }; static int access_count[MAX_DEV] = { 0, }; static char busy[MAX_DEV] = { 0, }; -static struct wait_queue *busy_wait; +static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int CurrentNReq; static int CurrentNSect; @@ -1125,8 +1126,8 @@ return -EINVAL; switch (cmd) { case HDIO_GETGEO: - /* HDIO_GETGEO is supported more for getting the partition's start - * sector... */ + /* HDIO_GETGEO is supported more for getting the partition's + * start sector... */ { struct hd_geometry *geo = (struct hd_geometry *)arg; /* just fake some geometry here, it's nonsense anyway; to make it * easy, use Adaptec's usual 64/32 mapping */ @@ -1147,19 +1148,18 @@ case BLKGETSIZE: /* Return device size */ return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects, (long *) arg); - + + case BLKROSET: + case BLKROGET: case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!inode->i_rdev) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_acsidisk(inode->i_rdev, 1); - RO_IOCTLS(inode->i_rdev,arg); + default: return -EINVAL; } diff -ur --new-file old/linux/drivers/block/acsi_slm.c new/linux/drivers/block/acsi_slm.c --- old/linux/drivers/block/acsi_slm.c Tue Dec 29 20:23:59 1998 +++ new/linux/drivers/block/acsi_slm.c Wed May 12 08:33:00 1999 @@ -143,8 +143,8 @@ static int SLMError; /* wait queues */ -static struct wait_queue *slm_wait; /* waiting for buffer */ -static struct wait_queue *print_wait; /* waiting for printing finished */ +static DECLARE_WAIT_QUEUE_HEAD(slm_wait); /* waiting for buffer */ +static DECLARE_WAIT_QUEUE_HEAD(print_wait); /* waiting for printing finished */ /* status codes */ #define SLMSTAT_OK 0x00 diff -ur --new-file old/linux/drivers/block/aec6210.c new/linux/drivers/block/aec6210.c --- old/linux/drivers/block/aec6210.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/aec6210.c Thu May 13 20:04:54 1999 @@ -0,0 +1,64 @@ +/* + * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998 + * + * Copyright (C) 1998 Andre Hedrick (hedrick@astro.dyer.vanderbilt.edu) + * + * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 + * pio 1 :: 40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 + * pio 2 :: 40: 08 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 + * pio 3 :: 40: 03 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * pio 4 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * dma 0 :: 40: 0a 07 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * dma 1 :: 40: 02 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * dma 2 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * 50: ff ff ff ff 00 06 04 00 00 00 00 00 00 00 00 00 + * + * udma 0 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00 + * + * udma 1 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00 + * + * udma 2 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00 + * + * auto :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 + * 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00 + * + * auto :: 40: 01 04 01 04 01 04 01 04 02 05 a6 cf 00 02 00 02 + * 50: ff ff ff ff aa 06 04 00 00 00 00 00 00 00 00 00 + * + * NO-Devices + * 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02 + * 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00 + + */ + +#include /* for CONFIG_BLK_DEV_IDEPCI */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +__initfunc(unsigned int pci_init_aec6210 (struct pci_dev *dev, const char *name)) +{ + if (dev->rom_address) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, + dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", + name, dev->rom_address); + } + return dev->irq; +} diff -ur --new-file old/linux/drivers/block/ali14xx.c new/linux/drivers/block/ali14xx.c --- old/linux/drivers/block/ali14xx.c Wed May 6 23:42:53 1998 +++ new/linux/drivers/block/ali14xx.c Thu May 13 20:04:54 1999 @@ -47,8 +47,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* port addresses for auto-detection */ diff -ur --new-file old/linux/drivers/block/alim15x3.c new/linux/drivers/block/alim15x3.c --- old/linux/drivers/block/alim15x3.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/alim15x3.c Thu May 13 20:04:54 1999 @@ -0,0 +1,347 @@ +/* + * linux/drivers/block/alim15x3.c Version 0.04 Feb. 8, 1999 + * + * Copyright (C) 1998-99 Michel Aubry, Maintainer + * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer + * Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer + * + * (U)DMA capable version of ali 1533/1543(C) + * + * Default disable (U)DMA on all devices execpt hard disks. + * This measure of overkill is needed to stablize the chipset code. + * + */ + +#include +#include +#include +#include + +#include + +#define DISPLAY_ALI_TIMINGS + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy); +extern int (*ali_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +struct pci_dev *bmide_dev; + +char *fifo[4] = { + "FIFO Off", + "FIFO On ", + "DMA mode", + "PIO mode" }; + +char *udmaT[8] = { + "1.5T", + " 2T", + "2.5T", + " 3T", + "3.5T", + " 4T", + " 6T", + " 8T" +}; + +char *channel_status[8] = { + "OK ", + "busy ", + "DRQ ", + "DRQ busy ", + "error ", + "error busy ", + "error DRQ ", + "error DRQ busy" +}; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + +__initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name)) +{ + byte confreg0 = 0, confreg1 =0, progif = 0; + int errors = 0; + + if (pci_read_config_byte(dev, 0x50, &confreg1)) + goto veryspecialsettingserror; + if (!(confreg1 & 0x02)) + if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02)) + goto veryspecialsettingserror; + + if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) + goto veryspecialsettingserror; + if (!(progif & 0x40)) { + /* + * The way to enable them is to set progif + * writable at 0x4Dh register, and set bit 6 + * of progif to 1: + */ + if (pci_read_config_byte(dev, 0x4d, &confreg0)) + goto veryspecialsettingserror; + if (confreg0 & 0x80) + if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80)) + goto veryspecialsettingserror; + if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40)) + goto veryspecialsettingserror; + if (confreg0 & 0x80) + if (pci_write_config_byte(dev, 0x4d, confreg0)) + errors++; + } + + if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40))) + goto veryspecialsettingserror; + + printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n", + name, errors ? "with Error(s)" : "Succeeded" ); + return 0; + +veryspecialsettingserror: + printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name); + return 0; +} + +int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + if (drive->media == ide_cdrom) { + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hd_driveid *id = drive->id; + byte cd_dma_fifo = 0; + + pci_read_config_byte(dev, 0x53, &cd_dma_fifo); + + if (((id->field_valid & 4) || (id->field_valid & 2)) && + (id->capability & 1) && hwif->autodma) { + unsigned long dma_set_bit = hwif->dma_base + 2; +#if 0 + if (cd_dma_fifo & 0x02) + pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x02); + pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01); +#else + pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01|0x02); +#endif + if (drive->select.b.unit & 0x01) { + outb(inb(dma_set_bit)|0x40, dma_set_bit); + } else { + outb(inb(dma_set_bit)|0x20, dma_set_bit); + } + } else { + if (cd_dma_fifo & 0x01) + pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x01); + pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x02); + } + } else if (drive->media != ide_disk) { + return ide_dmaproc(ide_dma_off_quietly, drive); + } + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +__initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif)) +{ + struct pci_dev *dev; + byte ideic, inmir; + byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, + 1, 11, 0, 12, 0, 14, 0, 15 }; + hwif->irq = hwif->channel ? 15 : 14; + for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */ + if (dev->vendor==PCI_VENDOR_ID_AL && + dev->device==PCI_DEVICE_ID_AL_M1533) + break; + if (dev) { + pci_read_config_byte(dev, 0x58, &ideic); + ideic = ideic & 0x03; + if ((hwif->channel && ideic == 0x03) || + (!hwif->channel && !ideic)) { + pci_read_config_byte(dev, 0x44, &inmir); + inmir = inmir & 0x0f; + hwif->irq = irq_routing_table[inmir]; + } else + if (hwif->channel && !(ideic & 0x01)) { + pci_read_config_byte(dev, 0x75, &inmir); + inmir = inmir & 0x0f; + hwif->irq = irq_routing_table[inmir]; + } + } +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) + bmide_dev = hwif->pci_dev; + ali_display_info = &ali_get_info; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + + if (hwif->dma_base) + hwif->dmaproc = &ali15x3_dmaproc; + return; +} + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) +static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy) +{ + byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1; + unsigned int bibma; + byte c0, c1; + byte rev, tmp; + char *p = buffer; + char *q; + + /* fetch rev. */ + pci_read_config_byte(bmide_dev, 0x08, &rev); + if (rev >= 0xc1) /* M1543C or newer */ + udmaT[7] = " ???"; + else + fifo[3] = " ??? "; + + /* first fetch bibma: */ + pci_read_config_dword(bmide_dev, 0x20, &bibma); + bibma = (bibma & 0xfff0) ; + /* + * at that point bibma+0x2 et bibma+0xa are byte + * registers to investigate: + */ + c0 = inb((unsigned short)bibma + 0x02); + c1 = inb((unsigned short)bibma + 0x0a); + + p += sprintf(p, + "\n Ali M15x3 Chipset.\n"); + p += sprintf(p, + " ------------------\n"); + pci_read_config_byte(bmide_dev, 0x78, ®53h); + p += sprintf(p, "PCI Clock: %d.\n", reg53h); + + pci_read_config_byte(bmide_dev, 0x53, ®53h); + p += sprintf(p, + "CD_ROM FIFO:%s, CD_ROM DMA:%s\n", + (reg53h & 0x02) ? "Yes" : "No ", + (reg53h & 0x01) ? "Yes" : "No " ); + pci_read_config_byte(bmide_dev, 0x74, ®53h); + p += sprintf(p, + "FIFO Status: contains %d Words, runs%s%s\n\n", + (reg53h & 0x3f), + (reg53h & 0x40) ? " OVERWR" : "", + (reg53h & 0x80) ? " OVERRD." : "." ); + + p += sprintf(p, + "-------------------primary channel-------------------secondary channel---------\n\n"); + + pci_read_config_byte(bmide_dev, 0x09, ®53h); + p += sprintf(p, + "channel status: %s %s\n", + (reg53h & 0x20) ? "On " : "Off", + (reg53h & 0x10) ? "On " : "Off" ); + + p += sprintf(p, + "both channels togth: %s %s\n", + (c0&0x80) ? "No " : "Yes", + (c1&0x80) ? "No " : "Yes" ); + + pci_read_config_byte(bmide_dev, 0x76, ®53h); + p += sprintf(p, + "Channel state: %s %s\n", + channel_status[reg53h & 0x07], + channel_status[(reg53h & 0x70) >> 4] ); + + pci_read_config_byte(bmide_dev, 0x58, ®5xh); + pci_read_config_byte(bmide_dev, 0x5c, ®5yh); + p += sprintf(p, + "Add. Setup Timing: %dT %dT\n", + (reg5xh & 0x07) ? (reg5xh & 0x07) : 8, + (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 ); + + pci_read_config_byte(bmide_dev, 0x59, ®5xh); + pci_read_config_byte(bmide_dev, 0x5d, ®5yh); + p += sprintf(p, + "Command Act. Count: %dT %dT\n" + "Command Rec. Count: %dT %dT\n\n", + (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, + (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, + (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, + (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 ); + + p += sprintf(p, + "----------------drive0-----------drive1------------drive0-----------drive1------\n\n"); + p += sprintf(p, + "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "Yes" : "No ", + (c0&0x40) ? "Yes" : "No ", + (c1&0x20) ? "Yes" : "No ", + (c1&0x40) ? "Yes" : "No " ); + + pci_read_config_byte(bmide_dev, 0x54, ®5xh); + pci_read_config_byte(bmide_dev, 0x55, ®5yh); + q = "FIFO threshold: %2d Words %2d Words %2d Words %2d Words\n"; + if (rev < 0xc1) { + if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) { + p += sprintf(p, q, 8, 8, 8, 8); + } else { + p += sprintf(p, q, + (reg5xh & 0x03) + 12, + ((reg5xh & 0x30)>>4) + 12, + (reg5yh & 0x03) + 12, + ((reg5yh & 0x30)>>4) + 12 ); + } + } else { + p += sprintf(p, q, + (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4, + (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4, + (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4, + (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4 ); + } + +#if 0 + p += sprintf(p, + "FIFO threshold: %2d Words %2d Words %2d Words %2d Words\n", + (reg5xh & 0x03) + 12, + ((reg5xh & 0x30)>>4) + 12, + (reg5yh & 0x03) + 12, + ((reg5yh & 0x30)>>4) + 12 ); +#endif + + p += sprintf(p, + "FIFO mode: %s %s %s %s\n", + fifo[((reg5xh & 0x0c) >> 2)], + fifo[((reg5xh & 0xc0) >> 6)], + fifo[((reg5yh & 0x0c) >> 2)], + fifo[((reg5yh & 0xc0) >> 6)] ); + + pci_read_config_byte(bmide_dev, 0x5a, ®5xh); + pci_read_config_byte(bmide_dev, 0x5b, ®5xh1); + pci_read_config_byte(bmide_dev, 0x5e, ®5yh); + pci_read_config_byte(bmide_dev, 0x5f, ®5yh1); + + p += sprintf(p,/* + "------------------drive0-----------drive1------------drive0-----------drive1------\n")*/ + "Dt RW act. Cnt %2dT %2dT %2dT %2dT\n" + "Dt RW rec. Cnt %2dT %2dT %2dT %2dT\n\n", + (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, + (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8, + (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, + (reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8, + (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, + (reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16, + (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16, + (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 ); + + p += sprintf(p, + "-----------------------------------UDMA Timings--------------------------------\n\n"); + + pci_read_config_byte(bmide_dev, 0x56, ®5xh); + pci_read_config_byte(bmide_dev, 0x57, ®5yh); + p += sprintf(p, + "UDMA: %s %s %s %s\n" + "UDMA timings: %s %s %s %s\n\n", + (reg5xh & 0x08) ? "OK" : "No", + (reg5xh & 0x80) ? "OK" : "No", + (reg5yh & 0x08) ? "OK" : "No", + (reg5yh & 0x80) ? "OK" : "No", + udmaT[(reg5xh & 0x07)], + udmaT[(reg5xh & 0x70) >> 4], + udmaT[reg5yh & 0x07], + udmaT[(reg5yh & 0x70) >> 4] ); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ diff -ur --new-file old/linux/drivers/block/amiflop.c new/linux/drivers/block/amiflop.c --- old/linux/drivers/block/amiflop.c Sun Nov 15 20:23:08 1998 +++ new/linux/drivers/block/amiflop.c Wed May 12 08:33:42 1999 @@ -167,9 +167,9 @@ /* request loop (trackbuffer) */ static volatile int fdc_busy = -1; static volatile int fdc_nested = 0; -static struct wait_queue *fdc_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); -static struct wait_queue *motor_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(motor_wait); static volatile int selected = -1; /* currently selected drive */ @@ -185,7 +185,7 @@ * request. */ static volatile char block_flag = 0; -static struct wait_queue *wait_fd_block = NULL; +static DECLARE_WAIT_QUEUE_HEAD(wait_fd_block); /* MS-Dos MFM Coding tables (should go quick and easy) */ static unsigned char mfmencode[16]={ @@ -196,7 +196,7 @@ /* floppy internal millisecond timer stuff */ static volatile int ms_busy = -1; -static struct wait_queue *ms_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(ms_wait); #define MS_TICKS ((amiga_eclock+50)/1000) /* diff -ur --new-file old/linux/drivers/block/ataflop.c new/linux/drivers/block/ataflop.c --- old/linux/drivers/block/ataflop.c Tue Dec 29 20:23:59 1998 +++ new/linux/drivers/block/ataflop.c Sun May 16 08:43:04 1999 @@ -93,6 +93,7 @@ #define MAJOR_NR FLOPPY_MAJOR #include +#include #define FD_MAX_UNITS 2 @@ -314,8 +315,8 @@ /* Synchronization of FDC access. */ static volatile int fdc_busy = 0; -static struct wait_queue *fdc_wait = NULL; -static struct wait_queue *format_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); +static DECLARE_WAIT_QUEUE_HEAD(format_wait); static unsigned int changed_floppies = 0xff, fake_change = 0; #define CHECK_CHANGE_DELAY HZ/2 @@ -1584,7 +1585,12 @@ device = inode->i_rdev; switch (cmd) { - RO_IOCTLS (device, param); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + return blk_ioctl(device, cmd, param); } drive = MINOR (device); type = drive >> 2; @@ -1620,22 +1626,6 @@ getprm.stretch = dtp->stretch; if (copy_to_user((void *)param, &getprm, sizeof(getprm))) return -EFAULT; - return 0; - case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (param > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = param; - return 0; - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], - (int *) param); - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); return 0; } if (!IOCTL_ALLOWED) diff -ur --new-file old/linux/drivers/block/blkpg.c new/linux/drivers/block/blkpg.c --- old/linux/drivers/block/blkpg.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/blkpg.c Sun May 16 08:43:04 1999 @@ -0,0 +1,288 @@ +/* + * Partition table and disk geometry handling + * + * This obsoletes the partition-handling code in genhd.c: + * Userspace can look at a disk in arbitrary format and tell + * the kernel what partitions there are on the disk, and how + * these should be numbered. + * It also allows one to repartition a disk that is being used. + * + * A single ioctl with lots of subfunctions: + * + * Device number stuff: + * get_whole_disk() (given the device number of a partition, find + * the device number of the encompassing disk) + * get_all_partitions() (given the device number of a disk, return the + * device numbers of all its known partitions) + * + * Partition stuff: + * add_partition() + * delete_partition() + * test_partition_in_use() (also for test_disk_in_use) + * + * Geometry stuff: + * get_geometry() + * set_geometry() + * get_bios_drivedata() + * + * For today, only the partition stuff - aeb, 990515 + */ + +#include +#include /* for BLKRASET, ... */ +#include /* for capable() */ +#include /* for set_device_ro() */ +#include +#include +#include /* for is_swap_partition() */ + +#include + +/* + * What is the data describing a partition? + * + * 1. a device number (kdev_t) + * 2. a starting sector and number of sectors (hd_struct) + * given in the part[] array of the gendisk structure for the drive. + * + * The number of sectors is replicated in the sizes[] array of + * the gendisk structure for the major, which again is copied to + * the blk_size[][] array. + * (However, hd_struct has the number of 512-byte sectors, + * g->sizes[] and blk_size[][] have the number of 1024-byte blocks.) + * Note that several drives may have the same major. + */ + +/* a linear search, superfluous when dev is a pointer */ +static struct gendisk *get_gendisk(kdev_t dev) { + struct gendisk *g; + int m = MAJOR(dev); + + for (g = gendisk_head; g; g = g->next) + if (g->major == m) + break; + return g; +} + +/* moved here from md.c - will be discarded later */ +char *partition_name (kdev_t dev) { + static char name[40]; /* kdevname returns 32 bytes */ + /* disk_name requires 32 bytes */ + struct gendisk *hd = get_gendisk (dev); + + if (!hd) { + sprintf (name, "[dev %s]", kdevname(dev)); + return (name); + } + + return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */ +} + +/* + * Add a partition. + * + * returns: EINVAL: bad parameters + * ENXIO: cannot find drive + * EBUSY: proposed partition overlaps an existing one + * or has the same number as an existing one + * 0: all OK. + */ +int add_partition(kdev_t dev, struct blkpg_partition *p) { + struct gendisk *g; + long long ppstart, pplength; + long pstart, plength; + int i, drive, first_minor, end_minor, minor; + + /* convert bytes to sectors, check for fit in a hd_struct */ + ppstart = (p->start >> 9); + pplength = (p->length >> 9); + pstart = ppstart; + plength = pplength; + if (pstart != ppstart || plength != pplength + || pstart < 0 || plength < 0) + return -EINVAL; + + /* find the drive major */ + g = get_gendisk(dev); + if (!g) + return -ENXIO; + + /* existing drive? */ + drive = (MINOR(dev) >> g->minor_shift); + first_minor = (drive << g->minor_shift); + end_minor = first_minor + g->max_p; + if (drive >= g->nr_real) + return -ENXIO; + + /* drive and partition number OK? */ + if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p) + return -EINVAL; + + /* partition number in use? */ + minor = first_minor + p->pno; + if (g->part[minor].nr_sects != 0) + return -EBUSY; + + /* overlap? */ + for (i=first_minor+1; ipart[i].start_sect || + pstart >= g->part[i].start_sect + g->part[i].nr_sects)) + return -EBUSY; + + /* all seems OK */ + g->part[minor].start_sect = pstart; + g->part[minor].nr_sects = plength; + if (g->sizes) + g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9)); + return 0; +} + +/* + * Delete a partition given by partition number + * + * returns: EINVAL: bad parameters + * ENXIO: cannot find partition + * EBUSY: partition is busy + * 0: all OK. + * + * Note that the dev argument refers to the entire disk, not the partition. + */ +int del_partition(kdev_t dev, struct blkpg_partition *p) { + struct gendisk *g; + kdev_t devp; + int drive, first_minor, minor; + + /* find the drive major */ + g = get_gendisk(dev); + if (!g) + return -ENXIO; + + /* drive and partition number OK? */ + drive = (MINOR(dev) >> g->minor_shift); + first_minor = (drive << g->minor_shift); + if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p) + return -EINVAL; + + /* existing drive and partition? */ + minor = first_minor + p->pno; + if (drive >= g->nr_real || g->part[minor].nr_sects == 0) + return -ENXIO; + + /* partition in use? Incomplete check for now. */ + devp = MKDEV(MAJOR(dev), minor); + if (get_super(devp) || /* mounted? */ + is_swap_partition(devp)) + return -EBUSY; + + /* all seems OK */ + fsync_dev(devp); + invalidate_buffers(devp); + + g->part[minor].start_sect = 0; + g->part[minor].nr_sects = 0; + if (g->sizes) + g->sizes[minor] = 0; + + return 0; +} + +int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + int len; + + if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) + return -EFAULT; + + switch (a.op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + len = a.datalen; + if (len < sizeof(struct blkpg_partition)) + return -EINVAL; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (a.op == BLKPG_ADD_PARTITION) + return add_partition(dev, &p); + else + return del_partition(dev, &p); + default: + return -EINVAL; + } +} + +/* + * Common ioctl's for block devices + */ + +int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg) +{ + int intval; + + switch (cmd) { + case BLKROSET: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (get_user(intval, (int *)(arg))) + return -EFAULT; + set_device_ro(dev, intval); + return 0; + case BLKROGET: + intval = (is_read_only(dev) != 0); + return put_user(intval, (int *)(arg)); + + case BLKRASET: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + if(!dev || arg > 0xff) + return -EINVAL; + read_ahead[MAJOR(dev)] = arg; + return 0; + case BLKRAGET: + if (!arg) + return -EINVAL; + return put_user(read_ahead[MAJOR(dev)], (long *) arg); + + case BLKFLSBUF: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!dev) + return -EINVAL; + fsync_dev(dev); + invalidate_buffers(dev); + return 0; + + case BLKSSZGET: + /* get block device sector size as needed e.g. by fdisk */ + intval = get_hardsect_size(dev); + return put_user(intval, (int *) arg); + +#if 0 + case BLKGETSIZE: + /* Today get_gendisk() requires a linear scan; + add this when dev has pointer type. */ + g = get_gendisk(dev); + if (!g) + longval = 0; + else + longval = g->part[MINOR(dev)].nr_sects; + return put_user(longval, (long *) arg); +#endif +#if 0 + case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return reread_partitions(dev, 1); +#endif + + case BLKPG: + return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg); + + default: + return -EINVAL; + } +} + diff -ur --new-file old/linux/drivers/block/buddha.c new/linux/drivers/block/buddha.c --- old/linux/drivers/block/buddha.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/buddha.c Thu May 13 20:04:54 1999 @@ -0,0 +1,161 @@ +/* + * linux/drivers/block/buddha.c -- Amiga Buddha and Catweasel IDE Driver + * + * Copyright (C) 1997 by Geert Uytterhoeven + * + * This driver was written by based on the specifications in README.buddha. + * + * 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. + * + * TODO: + * - test it :-) + * - tune the timings using the speed-register + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + /* + * The Buddha has 2 IDE interfaces, the Catweasel has 3 + */ + +#define BUDDHA_NUM_HWIFS 2 +#define CATWEASEL_NUM_HWIFS 3 + + + /* + * Bases of the IDE interfaces (relative to the board address) + */ + +#define BUDDHA_BASE1 0x800 +#define BUDDHA_BASE2 0xa00 +#define BUDDHA_BASE3 0xc00 + +static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { + BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 +}; + + + /* + * Offsets from one of the above bases + */ + +#define BUDDHA_DATA 0x00 +#define BUDDHA_ERROR 0x06 /* see err-bits */ +#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */ +#define BUDDHA_SECTOR 0x0e /* starting sector */ +#define BUDDHA_LCYL 0x12 /* starting cylinder */ +#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */ +#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ +#define BUDDHA_STATUS 0x1e /* see status-bits */ +#define BUDDHA_CONTROL 0x11a + +static int buddha_offsets[IDE_NR_PORTS] = { + BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, + BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL +}; + + + /* + * Other registers + */ + +#define BUDDHA_IRQ1 0xf00 /* MSB = 1, Harddisk is source of */ +#define BUDDHA_IRQ2 0xf40 /* interrupt */ +#define BUDDHA_IRQ3 0xf80 + +static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = { + BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 +}; + +#define BUDDHA_IRQ_MR 0xfc0 /* master interrupt enable */ + + + /* + * Board information + */ + +static u_long buddha_board = 0; +static int buddha_num_hwifs = -1; + + + /* + * Check and acknowledge the interrupt status + */ + +static int buddha_ack_intr(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x80)) + return 0; + return 1; +} + + + /* + * Any Buddha or Catweasel boards present? + */ + +static int find_buddha(void) +{ + u_int key; + const struct ConfigDev *cd; + + buddha_num_hwifs = 0; + if ((key = zorro_find(ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA, 0, 0))) + buddha_num_hwifs = BUDDHA_NUM_HWIFS; + else if ((key = zorro_find(ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL, 0, + 0))) + buddha_num_hwifs = CATWEASEL_NUM_HWIFS; + if (key) { + cd = zorro_get_board(key); + buddha_board = (u_long)cd->cd_BoardAddr; + if (buddha_board) { + buddha_board = ZTWO_VADDR(buddha_board); + /* write to BUDDHA_IRQ_MR to enable the board IRQ */ + *(char *)(buddha_board+BUDDHA_IRQ_MR) = 0; + zorro_config_board(key, 0); + } + } + return buddha_num_hwifs; +} + + + /* + * Probe for a Buddha or Catweasel IDE interface + * We support only _one_ of them, no multiple boards! + */ + +void buddha_init(void) +{ + hw_regs_t hw; + int i, index; + + if (buddha_num_hwifs < 0 && !find_buddha()) + return; + + for (i = 0; i < buddha_num_hwifs; i++) { + ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]), + buddha_offsets, 0, + (ide_ioreg_t)(buddha_board+buddha_irqports[i]), + buddha_ack_intr, IRQ_AMIGA_PORTS); + index = ide_register_hw(&hw, NULL); + if (index != -1) + printk("ide%d: %s IDE interface\n", index, + buddha_num_hwifs == BUDDHA_NUM_HWIFS ? "Buddha" : + "Catweasel"); + } +} diff -ur --new-file old/linux/drivers/block/cmd640.c new/linux/drivers/block/cmd640.c --- old/linux/drivers/block/cmd640.c Tue Jan 5 00:07:27 1999 +++ new/linux/drivers/block/cmd640.c Thu May 13 20:04:54 1999 @@ -110,8 +110,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff -ur --new-file old/linux/drivers/block/cmd646.c new/linux/drivers/block/cmd646.c --- old/linux/drivers/block/cmd646.c Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/block/cmd646.c Sat May 15 20:12:09 1999 @@ -1,4 +1,4 @@ -/* $Id: cmd646.c,v 1.11 1998/12/13 08:36:54 davem Exp $ +/* $Id: cmd646.c,v 1.12 1999/05/14 07:21:01 davem Exp $ * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because * there the "BIOS" has done all of the following already. @@ -12,8 +12,10 @@ #include #include #include +#include +#include + #include -#include "ide.h" static int cmd646_config_drive_for_dma(ide_drive_t *drive) { @@ -43,14 +45,14 @@ } /* This is fun. -DaveM */ -#define IDE_SETXFER 0x03 -#define IDE_SETFEATURE 0xef -#define IDE_DMA2_ENABLE 0x22 -#define IDE_DMA1_ENABLE 0x21 -#define IDE_DMA0_ENABLE 0x20 -#define IDE_UDMA2_ENABLE 0x42 -#define IDE_UDMA1_ENABLE 0x41 -#define IDE_UDMA0_ENABLE 0x40 +#define IDE_SETXFER SETFEATURES_XFER +#define IDE_SETFEATURE WIN_SETFEATURES +#define IDE_DMA2_ENABLE XFER_MW_DMA_2 +#define IDE_DMA1_ENABLE XFER_MW_DMA_1 +#define IDE_DMA0_ENABLE XFER_MW_DMA_0 +#define IDE_UDMA2_ENABLE XFER_UDMA_2 +#define IDE_UDMA1_ENABLE XFER_UDMA_1 +#define IDE_UDMA0_ENABLE XFER_UDMA_0 static __inline__ unsigned char dma2_bits_to_command(unsigned char bits) { @@ -212,10 +214,36 @@ return ide_dmaproc(func, drive); } +/* + * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old + * event order for DMA transfers. + */ +static int cmd646_1_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte dma_stat; + + if (func == ide_dma_end) { + drive->waiting_for_dma = 0; + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + return (dma_stat & 7) != 4; /* verify good DMA status */ + } + + /* Other cases are done by generic IDE-DMA code. */ + return cmd646_dmaproc(func, drive); +} + __initfunc(void ide_init_cmd646 (ide_hwif_t *hwif)) { struct pci_dev *dev = hwif->pci_dev; unsigned char mrdmode; + unsigned int class_rev; + + pci_read_config_dword(hwif->pci_dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; hwif->chipset = ide_cmd646; @@ -247,5 +275,9 @@ (void) pci_write_config_byte(dev, 0x58, 0x3f); (void) pci_write_config_byte(dev, 0x5b, 0x3f); - hwif->dmaproc = &cmd646_dmaproc; + if (class_rev == 0x01) { + hwif->dmaproc = &cmd646_1_dmaproc; + } else { + hwif->dmaproc = &cmd646_dmaproc; + } } diff -ur --new-file old/linux/drivers/block/cy82c693.c new/linux/drivers/block/cy82c693.c --- old/linux/drivers/block/cy82c693.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/cy82c693.c Thu May 13 20:04:54 1999 @@ -0,0 +1,431 @@ +/* + * linux/drivers/block/cy82c693.c Version 0.33 Jan. 23, 1999 + * + * Copyright (C) 1998, 1999 Andreas S. Krebs (akrebs@altavista.net), Maintainer + * Copyright (C) 1998 Andre Hedrick, Integrater + * + * CYPRESS CY82C693 chipset IDE controller + * + * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards. + * Writting the driver was quite simple, since most of the job is + * done by the generic pci-ide support. + * The hard part was finding the CY82C693's datasheet on Cypress's + * web page :-(. But Altavista solved this problem :-). + * + * + * Notes: + * - I recently got a 16.8G IBM DTTA, so I was able to test it with + * a large and fast disk - the results look great, so I'd say the + * driver is working fine :-) + * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA + * - this is my first linux driver, so there's probably a lot of room + * for optimizations and bug fixing, so fell free to do it. + * - use idebus=xx parameter to set PCI bus speed - needed to calc + * timings for PIO modes (default will be 40) + * - if using PIO mode it's a good idea to set the PIO mode and + * 32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda + * - I had some problems with my IBM DHEA with PIO modes < 2 + * (lost interrupts) ????? + * - first tests with DMA look okay, they seem to work, but there is a + * problem with sound - the BusMaster IDE TimeOut should fixed this + * + * + * History: + * ASK@1999-01-23: v0.33 made a few minor code clean ups + * removed DMA clock speed setting by default + * added boot message + * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut + * added support to set DMA Controller Clock Speed + * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes on some drive + * ASK@1998-10-29: v0.3 added support to set DMA modes + * ASK@1998-10-28: v0.2 added support to set PIO modes + * ASK@1998-10-27: v0.1 first version - chipset detection + * + */ + +#include +#include +#include +#include + +#include + +#include "ide_modes.h" + +/* the current version */ +#define CY82_VERSION "CY82C693U driver v0.33 99-01-23 Andreas S. Krebs (akrebs@altavista.net)" + +/* + * The following are used to debug the driver. + */ +#define CY82C693_DEBUG_LOGS 0 +#define CY82C693_DEBUG_INFO 0 + +/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */ +#undef CY82C693_SETDMA_CLOCK + +/* + * note: the value for busmaster timeout is tricky and i got it by trial and error ! + * using a to low value will cause DMA timeouts and drop IDE performance + * using a to high value will cause audio playback to scatter + * if you know a better value or how to calc it, please let me know + */ +#define BUSMASTER_TIMEOUT 0x50 /* twice the value written in cy82c693ub datasheet */ +/* + * the value above was tested on my machine and it seems to work okay + */ + +/* here are the offset definitions for the registers */ +#define CY82_IDE_CMDREG 0x04 +#define CY82_IDE_ADDRSETUP 0x48 +#define CY82_IDE_MASTER_IOR 0x4C +#define CY82_IDE_MASTER_IOW 0x4D +#define CY82_IDE_SLAVE_IOR 0x4E +#define CY82_IDE_SLAVE_IOW 0x4F +#define CY82_IDE_MASTER_8BIT 0x50 +#define CY82_IDE_SLAVE_8BIT 0x51 + +#define CY82_INDEX_PORT 0x22 +#define CY82_DATA_PORT 0x23 + +#define CY82_INDEX_CTRLREG1 0x01 +#define CY82_INDEX_CHANNEL0 0x30 +#define CY82_INDEX_CHANNEL1 0x31 +#define CY82_INDEX_TIMEOUT 0x32 + +/* the max PIO mode - from datasheet */ +#define CY82C693_MAX_PIO 4 + +/* the min and max PCI bus speed in MHz - from datasheet */ +#define CY82C963_MIN_BUS_SPEED 25 +#define CY82C963_MAX_BUS_SPEED 33 + +/* the struct for the PIO mode timings */ +typedef struct pio_clocks_s { + byte address_time; /* Address setup (clocks) */ + byte time_16r; /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */ + byte time_16w; /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */ + byte time_8; /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */ +} pio_clocks_t; + +/* + * calc clocks using bus_speed + * returns (rounded up) time in bus clocks for time in ns + */ +static int calc_clk (int time, int bus_speed) +{ + int clocks; + + clocks = (time*bus_speed+999)/1000 -1; + + if (clocks < 0) + clocks = 0; + + if (clocks > 0x0F) + clocks = 0x0F; + + return clocks; +} + +/* + * compute the values for the clock registers for PIO + * mode and pci_clk [MHz] speed + * + * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used + * for mode 3 and 4 drives 8 and 16-bit timings are the same + * + */ +static void compute_clocks (byte pio, pio_clocks_t *p_pclk) +{ + int clk1, clk2; + int bus_speed; + + bus_speed = ide_system_bus_speed(); /* get speed of PCI bus */ + /* we don't check against CY82C693's min and max speed, + * so you can play with the idebus=xx parameter + */ + + if (pio > CY82C693_MAX_PIO) + pio = CY82C693_MAX_PIO; + + /* let's calc the address setup time clocks */ + p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed); + + /* let's calc the active and recovery time clocks */ + clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed); + + /* calc recovery timing */ + clk2 = ide_pio_timings[pio].cycle_time - + ide_pio_timings[pio].active_time - + ide_pio_timings[pio].setup_time; + + clk2 = calc_clk(clk2, bus_speed); + + clk1 = (clk1<<4)|clk2; /* combine active and recovery clocks */ + + /* note: we use the same values for 16bit IOR and IOW + * those are all the same, since I don't have other + * timings than those from ide_modes.h + */ + + p_pclk->time_16r = (byte)clk1; + p_pclk->time_16w = (byte)clk1; + + /* what are good values for 8bit ?? */ + p_pclk->time_8 = (byte)clk1; +} + +/* + * set DMA mode a specific channel for CY82C693 + */ +static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) +{ + byte index; + byte data; + + if (mode>2) /* make sure we set a valid mode */ + mode = 2; + + if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */ + mode = drive->id->tDMA; + + index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1; + +#if CY82C693_DEBUG_LOGS + /* for debug let's show the previous values */ + + OUT_BYTE(index, CY82_INDEX_PORT); + data = IN_BYTE(CY82_DATA_PORT); + + printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1)); +#endif /* CY82C693_DEBUG_LOGS */ + + data = (byte)mode|(byte)(single<<2); + + OUT_BYTE(index, CY82_INDEX_PORT); + OUT_BYTE(data, CY82_DATA_PORT); + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single); +#endif /* CY82C693_DEBUG_INFO */ + + /* + * note: below we set the value for Bus Master IDE TimeOut Register + * I'm not absolutly sure what this does, but it solved my problem + * with IDE DMA and sound, so I now can play sound and work with + * my IDE driver at the same time :-) + * + * If you know the correct (best) value for this register please + * let me know - ASK + */ + + data = BUSMASTER_TIMEOUT; + OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); + OUT_BYTE(data, CY82_DATA_PORT); + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data); +#endif /* CY82C693_DEBUG_INFO */ +} + +/* + * used to set DMA mode for CY82C693 (single and multi modes) + */ +static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +{ + /* + * if the function is dma on, set dma mode for drive everything + * else is done by the defaul func + */ + if (func == ide_dma_on) { + struct hd_driveid *id = drive->id; + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "dma_on: %s\n", drive->name); +#endif /* CY82C693_DEBUG_INFO */ + + if (id != NULL) { + /* Enable DMA on any drive that has DMA (multi or single) enabled */ + if (id->field_valid & 2) { /* regular DMA */ + int mmode, smode; + + mmode = id->dma_mword & (id->dma_mword >> 8); + smode = id->dma_1word & (id->dma_1word >> 8); + + if (mmode != 0) + cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */ + else if (smode != 0) + cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */ + } + } + } + return ide_dmaproc(func, drive); +} + +/* + * tune ide drive - set PIO mode + */ +static void cy82c693_tune_drive (ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + pio_clocks_t pclk; + unsigned int addrCtrl; + + /* select primary or secondary channel */ + if (hwif->index > 0) /* drive is on the secondary channel */ + dev = dev->next; + +#if CY82C693_DEBUG_LOGS + /* for debug let's show the register values */ + + if (drive->select.b.unit == 0) { + /* + * get master drive registers + * address setup control register + * is 32 bit !!! + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + addrCtrl &= 0x0F; + + /* now let's get the remaining registers */ + pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r); + pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w); + pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8); + } else { + /* + * set slave drive registers + * address setup control register + * is 32 bit !!! + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + + addrCtrl &= 0xF0; + addrCtrl >>= 4; + + /* now let's get the remaining registers */ + pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r); + pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w); + pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8); + } + + printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); +#endif /* CY82C693_DEBUG_LOGS */ + + /* first let's calc the pio modes */ + pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL); + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio); +#endif /* CY82C693_DEBUG_INFO */ + + compute_clocks(pio, &pclk); /* let's calc the values for this PIO mode */ + + /* now let's write the clocks registers */ + if (drive->select.b.unit == 0) { + /* + * set master drive + * address setup control register + * is 32 bit !!! + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + + addrCtrl &= (~0xF); + addrCtrl |= (unsigned int)pclk.address_time; + pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); + + /* now let's set the remaining registers */ + pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r); + pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w); + pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8); + + addrCtrl &= 0xF; + } else { + /* + * set slave drive + * address setup control register + * is 32 bit !!! + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + + addrCtrl &= (~0xF0); + addrCtrl |= ((unsigned int)pclk.address_time<<4); + pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); + + /* now let's set the remaining registers */ + pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r); + pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w); + pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8); + + addrCtrl >>= 4; + addrCtrl &= 0xF; + } + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); +#endif /* CY82C693_DEBUG_INFO */ +} + +/* + * this function is called during init and is used to setup the cy82c693 chip + */ +static void init_cy82c693_chip (struct pci_dev *dev) +{ + static int initDone = 0; +#ifdef CY82C693_SETDMA_CLOCK + byte data; +#endif /* CY82C693_SETDMA_CLOCK */ + + if (initDone != 0) /* only perform setup once */ + return; + initDone = 1; + + /* write info about this verion of the driver */ + printk (KERN_INFO CY82_VERSION "\n"); + +#ifdef CY82C693_SETDMA_CLOCK + /* okay let's set the DMA clock speed */ + + OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT); + data = IN_BYTE(CY82_DATA_PORT); + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "CY82U693: Peripheral Configuration Register: 0x%X\n", data); +#endif /* CY82C693_DEBUG_INFO */ + + /* + * for some reason sometimes the DMA controller + * speed is set to ATCLK/2 ???? - we fix this here + * + * note: i don't know what causes this strange behaviour, + * but even changing the dma speed doesn't solve it :-( + * the ide performance is still only half the normal speed + * + * if anybody knows what goes wrong with my machine, please + * let me know - ASK + */ + + data |= 0x03; + + OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT); + OUT_BYTE(data, CY82_DATA_PORT); + +#if CY82C693_DEBUG_INFO + printk (KERN_INFO "CY82U693: New Peripheral Configuration Register: 0x%X\n", data); +#endif /* CY82C693_DEBUG_INFO */ + +#endif /* CY82C693_SETDMA_CLOCK */ +} + +/* + * the init function - called for each ide channel once + */ +__initfunc(void ide_init_cy82c693(ide_hwif_t *hwif)) +{ + hwif->chipset = ide_cy82c693; + hwif->dmaproc = &cy82c693_dmaproc; + hwif->tuneproc = &cy82c693_tune_drive; + + init_cy82c693_chip(hwif->pci_dev); +} + diff -ur --new-file old/linux/drivers/block/dtc2278.c new/linux/drivers/block/dtc2278.c --- old/linux/drivers/block/dtc2278.c Wed May 6 23:42:53 1998 +++ new/linux/drivers/block/dtc2278.c Thu May 13 20:04:54 1999 @@ -14,8 +14,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff -ur --new-file old/linux/drivers/block/falconide.c new/linux/drivers/block/falconide.c --- old/linux/drivers/block/falconide.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/falconide.c Thu May 13 20:04:54 1999 @@ -0,0 +1,66 @@ +/* + * linux/drivers/block/falconide.c -- Atari Falcon IDE Driver + * + * Created 12 Jul 1997 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + + /* + * Base of the IDE interface + */ + +#define ATA_HD_BASE 0xfff00000 + + /* + * Offsets from the above base + */ + +#define ATA_HD_DATA 0x00 +#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_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */ +#define ATA_HD_STATUS 0x1d /* see status-bits */ +#define ATA_HD_CONTROL 0x39 + +static int falconide_offsets[IDE_NR_PORTS] = { + ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, + ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1 +}; + + + /* + * Probe for a Falcon IDE interface + */ + +void falconide_init(void) +{ + if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { + hw_regs_t hw; + int index; + + ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets, + 0, 0, NULL, IRQ_MFP_IDE); + index = ide_register_hw(&hw, NULL); + + if (index != -1) + printk("ide%d: Falcon IDE interface\n", index); + } +} diff -ur --new-file old/linux/drivers/block/floppy.c new/linux/drivers/block/floppy.c --- old/linux/drivers/block/floppy.c Fri Mar 26 22:29:14 1999 +++ new/linux/drivers/block/floppy.c Sun May 16 08:43:04 1999 @@ -198,6 +198,7 @@ #define MAJOR_NR FLOPPY_MAJOR #include +#include #include /* for the compatibility eject ioctl */ #ifndef fd_get_dma_residue @@ -466,7 +467,9 @@ #define FD_COMMAND_OKAY 3 static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0; -static struct wait_queue *fdc_wait = NULL, *command_done = NULL; +static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); +static DECLARE_WAIT_QUEUE_HEAD(command_done); + #define NO_SIGNAL (!interruptible || !signal_pending(current)) #define CALL(x) if ((x) == -EINTR) return -EINTR #define ECALL(x) if ((ret = (x))) return ret; @@ -3291,7 +3294,7 @@ LOCK_FDC(drive,1); if (cmd != FDDEFPRM) /* notice a disk change immediately, else - * we loose our settings immediately*/ + * we lose our settings immediately*/ CALL(poll_drive(1, FD_RAW_NEED_DISK)); user_params[drive] = *g; if (buffer_drive == drive) @@ -3400,7 +3403,12 @@ device = inode->i_rdev; switch (cmd) { - RO_IOCTLS(device,param); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + return blk_ioctl(device, cmd, param); } type = TYPE(device); drive = DRIVE(device); @@ -3430,19 +3438,6 @@ loc.start = 0; return _COPYOUT(loc); } - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(param > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = param; - return 0; - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], - (long *) param); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKGETSIZE: ECALL(get_floppy_geometry(drive, type, &g)); diff -ur --new-file old/linux/drivers/block/gayle.c new/linux/drivers/block/gayle.c --- old/linux/drivers/block/gayle.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/gayle.c Thu May 13 20:04:54 1999 @@ -0,0 +1,169 @@ +/* + * linux/drivers/block/gayle.c -- Amiga Gayle IDE Driver + * + * Created 9 Jul 1997 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + /* + * Bases of the IDE interfaces + */ + +#define GAYLE_BASE_4000 0xdd2020 /* A4000/A4000T */ +#define GAYLE_BASE_1200 0xda0000 /* A1200/A600 */ + + /* + * Offsets from one of the above bases + */ + +#define GAYLE_DATA 0x00 +#define GAYLE_ERROR 0x06 /* see err-bits */ +#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */ +#define GAYLE_SECTOR 0x0e /* starting sector */ +#define GAYLE_LCYL 0x12 /* starting cylinder */ +#define GAYLE_HCYL 0x16 /* high byte of starting cyl */ +#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ +#define GAYLE_STATUS 0x1e /* see status-bits */ +#define GAYLE_CONTROL 0x101a + +static int gayle_offsets[IDE_NR_PORTS] = { + GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, + GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 +}; + + + /* + * These are at different offsets from the base + */ + +#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */ +#define GAYLE_IRQ_1200 0xda9000 /* interrupt */ + + + /* + * Offset of the secondary port for IDE doublers + * Note that GAYLE_CONTROL is NOT available then! + */ + +#define GAYLE_NEXT_PORT 0x1000 + +#ifndef CONFIG_BLK_DEV_IDEDOUBLER +#define GAYLE_NUM_HWIFS 1 +#define GAYLE_NUM_PROBE_HWIFS GAYLE_NUM_HWIFS +#define GAYLE_HAS_CONTROL_REG 1 +#else /* CONFIG_BLK_DEV_IDEDOUBLER */ +#define GAYLE_NUM_HWIFS 2 +#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ + GAYLE_NUM_HWIFS-1) +#define GAYLE_HAS_CONTROL_REG (!ide_doubler) +int ide_doubler = 0; /* support IDE doublers? */ +#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + + + /* + * Check and acknowledge the interrupt status + */ + +static int gayle_ack_intr_a4000(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x80)) + return 0; + return 1; +} + +static int gayle_ack_intr_a1200(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x80)) + return 0; + (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]); + outb(0x7c | (ch & 0x03), hwif->io_ports[IDE_IRQ_OFFSET]); + return 1; +} + + /* + * Probe for a Gayle IDE interface (and optionally for an IDE doubler) + */ + +void gayle_init(void) +{ + int a4000, i; + + if (!MACH_IS_AMIGA) + return; + + if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE)) + return; + + for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) { + ide_ioreg_t base, ctrlport, irqport; + ide_ack_intr_t *ack_intr; + hw_regs_t hw; + int index; + + if (a4000) { + base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_4000); + irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000); + ack_intr = gayle_ack_intr_a4000; + } else { + base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_1200); + irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200); + ack_intr = gayle_ack_intr_a1200; + } + + if (GAYLE_HAS_CONTROL_REG) + ctrlport = base + GAYLE_CONTROL; + else + ctrlport = 0; + + base += i*GAYLE_NEXT_PORT; + + ide_setup_ports(&hw, base, gayle_offsets, + ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS); + + index = ide_register_hw(&hw, NULL); + if (index != -1) { + switch (i) { + case 0: + printk("ide%d: Gayle IDE interface (A%d style)\n", index, + a4000 ? 4000 : 1200); + break; +#ifdef CONFIG_BLK_DEV_IDEDOUBLER + case 1: + printk("ide%d: IDE doubler\n", index); + break; +#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + } + } +#if 1 /* TESTING */ + if (i == 1) { + volatile u_short *addr = (u_short *)base; + u_short data; + printk("+++ Probing for IDE doubler... "); + *addr = 0xffff; + data = *addr; + printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data); + } +#endif /* TESTING */ + } +} diff -ur --new-file old/linux/drivers/block/genhd.c new/linux/drivers/block/genhd.c --- old/linux/drivers/block/genhd.c Thu Jun 3 04:26:58 1999 +++ new/linux/drivers/block/genhd.c Thu Jun 3 04:28:25 1999 @@ -67,10 +67,10 @@ #endif /* - * disk_name() is used by genhd.c and md.c. - * It formats the devicename of the indicated disk - * into the supplied buffer, and returns a pointer - * to that same buffer (for convenience). + * disk_name() is used by genhd.c and blkpg.c. + * It formats the devicename of the indicated disk into + * the supplied buffer (of size at least 32), and returns + * a pointer to that same buffer (for convenience). */ char *disk_name (struct gendisk *hd, int minor, char *buf) { @@ -84,6 +84,10 @@ * This requires special handling here. */ switch (hd->major) { + case IDE7_MAJOR: + unit += 2; + case IDE6_MAJOR: + unit += 2; case IDE5_MAJOR: unit += 2; case IDE4_MAJOR: @@ -118,7 +122,7 @@ static void add_partition (struct gendisk *hd, int minor, int start, int size) { - char buf[8]; + char buf[32]; hd->part[minor].start_sect = start; hd->part[minor].nr_sects = size; printk(" %s", disk_name(hd, minor, buf)); @@ -131,12 +135,12 @@ SYS_IND(p) == LINUX_EXTENDED_PARTITION); } -static int sector_partition_scale(kdev_t dev) +int get_hardsect_size(kdev_t dev) { - if (hardsect_size[MAJOR(dev)] != NULL) - return (hardsect_size[MAJOR(dev)][MINOR(dev)]/512); - else - return (1); + if (hardsect_size[MAJOR(dev)] != NULL) + return hardsect_size[MAJOR(dev)][MINOR(dev)]; + else + return 512; } static unsigned int get_ptable_blocksize(kdev_t dev) @@ -206,7 +210,7 @@ struct partition *p; unsigned long first_sector, first_size, this_sector, this_size; int mask = (1 << hd->minor_shift) - 1; - int sector_size = sector_partition_scale(dev); + int sector_size = get_hardsect_size(dev) / 512; int i; first_sector = hd->part[MINOR(dev)].start_sect; @@ -450,7 +454,7 @@ struct partition *p; unsigned char *data; int mask = (1 << hd->minor_shift) - 1; - int sector_size = sector_partition_scale(dev); + int sector_size = get_hardsect_size(dev) / 512; #ifdef CONFIG_BSD_DISKLABEL /* no bsd disklabel as a default */ kdev_t bsd_kdev = 0; @@ -880,10 +884,7 @@ int blocksize; old_blocksize = get_ptable_blocksize(dev); - if (hardsect_size[MAJOR(dev)] != NULL) - blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; - else - blocksize = 512; + blocksize = get_hardsect_size(dev); set_blocksize(dev,blocksize); res = 0; @@ -1220,7 +1221,7 @@ { static int first_time = 1; unsigned long first_sector; - char buf[8]; + char buf[32]; if (first_time) printk("Partition check:\n"); @@ -1304,28 +1305,21 @@ int end_minor = dev->max_nr * dev->max_p; blk_size[dev->major] = NULL; - for (i = 0 ; i < end_minor; i++) { + for (i = 0; i < end_minor; i++) { dev->part[i].start_sect = 0; dev->part[i].nr_sects = 0; + dev->sizes[i] = 0; } dev->init(dev); - for (drive = 0 ; drive < dev->nr_real ; drive++) { - int first_minor = drive << dev->minor_shift; - current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); - } - if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = 0; i < end_minor; i++) - dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); - blk_size[dev->major] = dev->sizes; - } + for (drive = 0; drive < dev->nr_real; drive++) + resetup_one_dev(dev, drive); } __initfunc(void device_setup(void)) { extern void console_map_init(void); #ifdef CONFIG_PARPORT - extern int parport_init(void); + extern int parport_init(void) __init; #endif #ifdef CONFIG_MD_BOOT extern void md_setup_drive(void) __init; diff -ur --new-file old/linux/drivers/block/hd.c new/linux/drivers/block/hd.c --- old/linux/drivers/block/hd.c Thu Feb 25 01:27:53 1999 +++ new/linux/drivers/block/hd.c Sun May 16 08:43:04 1999 @@ -68,7 +68,7 @@ static char special_op[MAX_HD] = { 0, }; static int access_count[MAX_HD] = {0, }; static char busy[MAX_HD] = {0, }; -static struct wait_queue * busy_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int reset = 0; static int hd_error = 0; @@ -604,31 +604,25 @@ g.start = hd[MINOR(inode->i_rdev)].start_sect; return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - return put_user(read_ahead[MAJOR(inode->i_rdev)], - (long *) arg); + case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; return put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_hddisk(inode->i_rdev, 1); - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + default: return -EINVAL; } @@ -836,7 +830,7 @@ if (DEVICE_BUSY || USAGE > maxusage) { restore_flags(flags); return -EBUSY; - }; + } DEVICE_BUSY = 1; restore_flags(flags); @@ -854,7 +848,7 @@ invalidate_buffers(devi); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; - }; + } #ifdef MAYBE_REINIT MAYBE_REINIT; diff -ur --new-file old/linux/drivers/block/hpt343.c new/linux/drivers/block/hpt343.c --- old/linux/drivers/block/hpt343.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/hpt343.c Sat May 15 03:50:32 1999 @@ -0,0 +1,393 @@ +/* + * linux/drivers/block/hpt343.c Version 0.23 May 12, 1999 + * + * Copyright (C) 1998-99 Andre Hedrick + * (hedrick@astro.dyer.vanderbilt.edu) + * + * 00:12.0 Unknown mass storage controller: + * Triones Technologies, Inc. + * Unknown device 0003 (rev 01) + * + * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010) + * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030) + * hde: DMA 2 (0x0000 0x0002) (0x0000 0x0010) + * hdf: DMA 2 (0x0002 0x0012) (0x0010 0x0030) + * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) + * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include /* for CONFIG_BLK_DEV_IDEPCI */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#ifndef SPLIT_BYTE +#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) +#endif + +#define HPT343_DEBUG_DRIVE_INFO 0 +#define HPT343_DISABLE_ALL_DMAING 0 +#define HPT343_DMA_DISK_ONLY 0 + +extern char *ide_xfer_verbose (byte xfer_rate); + +static void hpt343_clear_chipset (ide_drive_t *drive) +{ + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + unsigned int reg1 = 0, tmp1 = 0; + unsigned int reg2 = 0, tmp2 = 0; + + pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); + pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); + tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); + tmp2 = ((0x00 << drive_number) | reg2); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); +} + +static int hpt343_tune_chipset (ide_drive_t *drive, byte speed) +{ + int err; + byte hi_speed, lo_speed; + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + unsigned int reg1 = 0, tmp1 = 0; + unsigned int reg2 = 0, tmp2 = 0; + + SPLIT_BYTE(speed, hi_speed, lo_speed); + + if (hi_speed & 7) { + hi_speed = (hi_speed & 4) ? 0x01 : 0x10; + } else { + lo_speed <<= 5; + lo_speed >>= 5; + } + + pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); + pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); + tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); + tmp2 = ((hi_speed << drive_number) | reg2); + err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); + +#if HPT343_DEBUG_DRIVE_INFO + printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ + " (0x%02x 0x%02x) 0x%04x\n", + drive->name, ide_xfer_verbose(speed), + drive_number, reg1, tmp1, reg2, tmp2, + hi_speed, lo_speed, err); +#endif /* HPT343_DEBUG_DRIVE_INFO */ + + return(err); +} + +/* + * This allows the configuration of ide_pci chipset registers + * for cards that learn about the drive's UDMA, DMA, PIO capabilities + * after the drive is reported by the OS. Initally for designed for + * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. + */ +static int config_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed = 0x00; + +#if HPT343_DISABLE_ALL_DMAING + return ((int) ide_dma_off); +#elif HPT343_DMA_DISK_ONLY + if (drive->media != ide_disk) + return ((int) ide_dma_off_quietly); +#endif /* HPT343_DISABLE_ALL_DMAING */ + + if (id->dma_ultra & 0x0004) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_2; + } else if (id->dma_ultra & 0x0002) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_1; + } else if (id->dma_ultra & 0x0001) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) hpt343_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void config_chipset_for_pio (ide_drive_t *drive) +{ + unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + + byte timing, speed, pio; + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + + switch(timing) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: + speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + break; + } + + (void) hpt343_tune_chipset(drive, speed); +} + +#if 0 +static void hpt343_tune_drive (ide_drive_t *drive, byte pio) +{ +} +#endif + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x0007) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + + config_chipset_for_pio(drive); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * hpt343_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + * + * This is specific to the HPT343 UDMA bios-less chipset + * and HPT345 UDMA bios chipset (stamped HPT363) + * by HighPoint|Triones Technologies, Inc. + */ + +int hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + hpt343_clear_chipset(drive); + return config_drive_xfer_rate(drive); +#if 0 + case ide_dma_off: + case ide_dma_off_quietly: + case ide_dma_on: + case ide_dma_check: + return config_drive_xfer_rate(drive); + case ide_dma_read: + case ide_dma_write: + case ide_dma_begin: + case ide_dma_end: + case ide_dma_test_irq: +#endif + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +/* + * If the BIOS does not set the IO base addaress to XX00, 343 will fail. + */ +#define HPT343_PCI_INIT_REG 0x80 + +__initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name)) +{ + int i; + unsigned short cmd; + unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; +#if 0 + unsigned char misc10 = inb(hpt343IoBase + 0x0010); + unsigned char misc11 = inb(hpt343IoBase + 0x0011); +#endif + + pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x00); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + + dev->base_address[0] = (hpt343IoBase + 0x20); + dev->base_address[1] = (hpt343IoBase + 0x34); + dev->base_address[2] = (hpt343IoBase + 0x28); + dev->base_address[3] = (hpt343IoBase + 0x3c); + + for(i=0; i<4; i++) + dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; + + /* + * Since 20-23 can be assigned and are R/W, we correct them. + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]); + pci_write_config_word(dev, PCI_COMMAND, cmd); + +#if 0 + outb(misc10|0x78, (hpt343IoBase + 0x0010)); + outb(misc11, (hpt343IoBase + 0x0011)); +#endif + +#ifdef DEBUG + printk("%s: 0x%02x 0x%02x\n", + (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name, + inb(hpt343IoBase + 0x0010), + inb(hpt343IoBase + 0x0011)); +#endif + + if (cmd & PCI_COMMAND_MEMORY) { + if (dev->rom_address) { + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address); + } + } else { + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + } + return dev->irq; +} + +__initfunc(void ide_init_hpt343 (ide_hwif_t *hwif)) +{ + if (hwif->dma_base) { + unsigned short pcicmd = 0; + + pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); + hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; + hwif->dmaproc = &hpt343_dmaproc; + } +} diff -ur --new-file old/linux/drivers/block/ht6560b.c new/linux/drivers/block/ht6560b.c --- old/linux/drivers/block/ht6560b.c Wed Jun 24 23:30:09 1998 +++ new/linux/drivers/block/ht6560b.c Thu May 13 20:04:54 1999 @@ -57,8 +57,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff -ur --new-file old/linux/drivers/block/ide-cd.c new/linux/drivers/block/ide-cd.c --- old/linux/drivers/block/ide-cd.c Tue Apr 13 01:18:26 1999 +++ new/linux/drivers/block/ide-cd.c Thu May 13 20:04:54 1999 @@ -258,13 +258,14 @@ #include #include #include +#include + #include #include #include #include #include -#include "ide.h" #include "ide-cd.h" /**************************************************************************** @@ -670,7 +671,8 @@ OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG); OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG); - OUT_BYTE (drive->ctl, IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl, IDE_CONTROL_REG); if (info->dma) (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); @@ -2940,7 +2942,19 @@ else printk (" drive"); - printk (", %dkB Cache\n", ntohs(buf.cap.buffer_size)); + printk (", %dkB Cache", ntohs(buf.cap.buffer_size)); + + if (drive->using_dma) { + if ((drive->id->field_valid & 4) && + (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) { + printk(", UDMA"); /* UDMA BIOS-enabled! */ + } else if (drive->id->field_valid & 4) { + printk(", (U)DMA"); /* Can be BIOS-enabled! */ + } else { + printk(", DMA"); + } + } + printk("\n"); return nslots; } @@ -2956,6 +2970,53 @@ ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); } +#ifdef CONFIG_IDECD_SLOTS +static void ide_cdrom_slot_check (ide_drive_t *drive, int nslots) +{ + tracktype tracks; + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *devinfo = &info->devinfo; + int slot_count = 0, drive_stat = 0, tmp; + + for (slot_count=0;slot_countis_changer) { + ide_cdrom_slot_check(drive, nslots); + } +#endif /* CONFIG_IDECD_SLOTS */ return 0; } diff -ur --new-file old/linux/drivers/block/ide-disk.c new/linux/drivers/block/ide-disk.c --- old/linux/drivers/block/ide-disk.c Thu Mar 11 02:49:43 1999 +++ new/linux/drivers/block/ide-disk.c Thu May 13 20:04:54 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.08 Dec 10, 1998 + * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -25,12 +25,16 @@ * process of adding new ATA4 compliance. * fixed problems in allowing fdisk to see * the entire disk. + * Version 1.09 added increment of rq->sector in ide_multwrite + * added UDMA 3/4 reporting */ -#define IDEDISK_VERSION "1.08" +#define IDEDISK_VERSION "1.09" #undef REALLY_SLOW_IO /* most systems can safely undef this */ +#define _IDE_DISK_C /* Tell linux/hdsmart.h it's really us */ + #include #include #include @@ -44,14 +48,13 @@ #include #include #include +#include #include #include #include #include -#include "ide.h" - static void idedisk_bswap_data (void *buffer, int wcount) { u16 *p = buffer; @@ -101,6 +104,15 @@ id->cyls = lba_sects / (16 * 63); /* correct cyls */ return 1; /* lba_capacity is our only option */ } + /* + * ... and at least one TLA VBC has POS instead of brain and can't + * tell 16 from 15. + */ + if ((id->lba_capacity >= 15481935) && (id->cyls == 0x3fff) && + (id->heads == 15) && (id->sectors == 63)) { + id->cyls = lba_sects / (15 * 63); /* correct cyls */ + return 1; /* lba_capacity is our only option */ + } /* perform a rough sanity check on lba_sects: within 10% is "okay" */ if ((lba_sects - chs_sects) < _10_percent) { return 1; /* lba_capacity is good */ @@ -221,6 +233,9 @@ drive->name, rq->sector, (unsigned long) rq->buffer, nsect, rq->nr_sectors - nsect); #endif +#ifdef CONFIG_BLK_DEV_PDC4030 + rq->sector += nsect; +#endif if ((rq->nr_sectors -= nsect) <= 0) break; if ((rq->current_nr_sectors -= nsect) == 0) { @@ -279,7 +294,11 @@ { byte stat = GET_STAT(); +#if 0 + if (OK_STAT(stat,READY_STAT,BAD_STAT) || drive->mult_req == 0) { +#else if (OK_STAT(stat,READY_STAT,BAD_STAT)) { +#endif drive->mult_count = drive->mult_req; } else { drive->mult_req = drive->mult_count = 0; @@ -322,14 +341,21 @@ int use_pdc4030_io = 0; #endif /* CONFIG_BLK_DEV_PDC4030 */ - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); #ifdef CONFIG_BLK_DEV_PDC4030 +#ifdef CONFIG_BLK_DEV_PDC4030_TESTING + if (IS_PDC4030_DRIVE) { + use_pdc4030_io = 1; + } +#else if (IS_PDC4030_DRIVE) { if (hwif->channel != 0 || rq->cmd == READ) { use_pdc4030_io = 1; } } +#endif /* CONFIG_BLK_DEV_PDC4030_TESTING */ if (drive->select.b.lba || use_pdc4030_io) { #else /* !CONFIG_BLK_DEV_PDC4030 */ if (drive->select.b.lba) { @@ -760,9 +786,12 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); if (drive->using_dma) { - if ((id->field_valid & 4) && - (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { - printk(", UDMA"); /* UDMA BIOS-enabled! */ + if ((id->field_valid & 4) && (id->word93 & 0x2000) && + (id->dma_ultra & (id->dma_ultra >> 11) & 3)) { + printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ + } else if ((id->field_valid & 4) && + (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { + printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ } else if (id->field_valid & 4) { printk(", (U)DMA"); /* Can be BIOS-enabled! */ } else { @@ -786,17 +815,17 @@ drive->mult_count = 0; if (id->max_multsect) { -#if 1 /* original, pre IDE-NFG, per request of AC */ +#ifdef CONFIG_IDEDISK_MULTI_MODE + id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; + id->multsect_valid = id->multsect ? 1 : 0; + drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; + drive->special.b.set_multmode = drive->mult_req ? 1 : 0; +#else /* original, pre IDE-NFG, per request of AC */ drive->mult_req = INITIAL_MULT_COUNT; if (drive->mult_req > id->max_multsect) drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) drive->special.b.set_multmode = 1; -#else - id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; - id->multsect_valid = id->multsect ? 1 : 0; - drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; - drive->special.b.set_multmode = drive->mult_req ? 1 : 0; #endif } drive->no_io_32bit = id->dword_io ? 1 : 0; diff -ur --new-file old/linux/drivers/block/ide-dma.c new/linux/drivers/block/ide-dma.c --- old/linux/drivers/block/ide-dma.c Tue May 11 23:58:46 1999 +++ new/linux/drivers/block/ide-dma.c Thu May 13 20:04:54 1999 @@ -1,5 +1,12 @@ /* - * linux/drivers/block/ide-dma.c Version 4.08 December 31, 1997 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * + * Copyright (c) 1999 Andre Hedrick + * May be copied or modified under the terms of the GNU General Public License + */ + +/* + * Special Thanks to Mark for his Six years of work. * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -24,7 +31,7 @@ * * Use "hdparm -i" to view modes supported by a given drive. * - * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling + * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling * DMA support, but must be (re-)compiled against this kernel version or later. * * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting. @@ -79,11 +86,51 @@ #include #include #include +#include #include #include -#include "ide.h" +#define IDE_DMA_NEW_LISTINGS 0 + +#if IDE_DMA_NEW_LISTINGS +struct drive_list_entry { + char * id_model; + char * id_firmware; +}; + +struct drive_list_entry drive_whitelist [] = { + + { "Micropolis 2112A" , "ALL" }, + { "CONNER CTMA 4000" , "ALL" }, + { "CONNER CTT8000-A" , "ALL" }, + { "ST34342A" , "ALL" }, + { 0 , 0 } +}; + +struct drive_list_entry drive_blacklist [] = { + + { "WDC AC11000H" , "ALL" }, + { "WDC AC22100H" , "ALL" }, + { "WDC AC32500H" , "ALL" }, + { "WDC AC33100H" , "ALL" }, + { "WDC AC31600H" , "ALL" }, + { "WDC AC32100H" , "24.09P07" }, + { "WDC AC23200L" , "21.10N21" }, + { 0 , 0 } + +}; + +int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) +{ + for ( ; drive_table->id_model ; drive_table++) + if ((!strcmp(drive_table->id_model, id->model)) && + ((!strstr(drive_table->id_firmware, id->fw_rev)) || + (!strcmp(drive_table->id_firmware, "ALL")))) + return 1; + return 0; +} +#else /* !IDE_DMA_NEW_LISTINGS */ /* * good_dma_drives() lists the model names (from "hdparm -i") @@ -109,11 +156,14 @@ */ const char *bad_dma_drives[] = {"WDC AC11000H", "WDC AC22100H", + "WDC AC32100H", "WDC AC32500H", "WDC AC33100H", "WDC AC31600H", NULL}; +#endif /* IDE_DMA_NEW_LISTINGS */ + /* * Our Physical Region Descriptor (PRD) table should be large enough * to handle the biggest I/O request we are likely to see. Since requests @@ -164,11 +214,12 @@ * Returns 0 if all went okay, returns 1 otherwise. * May also be invoked from trm290.c */ -int ide_build_dmatable (ide_drive_t *drive) +int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func) { struct request *rq = HWGROUP(drive)->rq; struct buffer_head *bh = rq->bh; unsigned int size, addr, *table = (unsigned int *)HWIF(drive)->dmatable; + unsigned char *virt_addr; #ifdef CONFIG_BLK_DEV_TRM290 unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290); #else @@ -185,11 +236,13 @@ * than two possibly non-adjacent physical 4kB pages. */ if (bh == NULL) { /* paging requests have (rq->bh == NULL) */ - addr = virt_to_bus (rq->buffer); + virt_addr = rq->buffer; + addr = virt_to_bus (virt_addr); size = rq->nr_sectors << 9; } else { /* group sequential buffers into one large buffer */ - addr = virt_to_bus (bh->b_data); + virt_addr = bh->b_data; + addr = virt_to_bus (virt_addr); size = bh->b_size; while ((bh = bh->b_reqnext) != NULL) { if ((addr + size) != virt_to_bus (bh->b_data)) @@ -206,6 +259,20 @@ printk("%s: misaligned DMA buffer\n", drive->name); return 0; } + + /* + * Some CPUs without cache snooping need to invalidate/write + * back their caches before DMA transfers to guarantee correct + * data. -- rmk + */ + if (size) { + if (func == ide_dma_read) { + dma_cache_inv((unsigned int)virt_addr, size); + } else { + dma_cache_wback((unsigned int)virt_addr, size); + } + } + while (size) { if (++count >= PRD_ENTRIES) { printk("%s: DMA table too small\n", drive->name); @@ -224,10 +291,17 @@ } } } while (bh != NULL); - if (!count) + if (!count) { printk("%s: empty DMA table?\n", drive->name); - else if (!is_trm290_chipset) - *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */ + } else { + if (!is_trm290_chipset) + *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */ + /* + * Some CPUs need to flush the DMA table to physical RAM + * before DMA can start. -- rmk + */ + dma_cache_wback((unsigned long)HWIF(drive)->dmatable, count * sizeof(unsigned int) * 2); + } return count; } @@ -238,9 +312,22 @@ */ int check_drive_lists (ide_drive_t *drive, int good_bad) { - const char **list; struct hd_driveid *id = drive->id; +#if IDE_DMA_NEW_LISTINGS + + if (good_bad) { + return in_drive_list(id, drive_whitelist); + } else { + int blacklist = in_drive_list(id, drive_blacklist); + if (blacklist) + printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); + return(blacklist); + } +#else /* !IDE_DMA_NEW_LISTINGS */ + + const char **list; + if (good_bad) { /* Consult the list of known "good" drives */ list = good_dma_drives; @@ -259,6 +346,7 @@ } } } +#endif /* IDE_DMA_NEW_LISTINGS */ return 0; } @@ -269,18 +357,24 @@ if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ - if (check_drive_lists(drive, BAD_DMA_DRIVE)) + if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); +#if 0 + /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ + if ((id->field_valid & 4) && (id->word93 & 0x2000)) + if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) + return hwif->dmaproc(ide_dma_on, drive); +#endif /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ - if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) + if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) return hwif->dmaproc(ide_dma_on, drive); /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */ if (id->field_valid & 2) /* regular DMA */ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) return hwif->dmaproc(ide_dma_on, drive); /* Consult the list of known "good" drives */ - if (check_drive_lists(drive, GOOD_DMA_DRIVE)) + if (ide_dmaproc(ide_dma_good_drive, drive)) return hwif->dmaproc(ide_dma_on, drive); } return hwif->dmaproc(ide_dma_off_quietly, drive); @@ -321,7 +415,7 @@ case ide_dma_read: reading = 1 << 3; case ide_dma_write: - if (!(count = ide_build_dmatable(drive))) + if (!(count = ide_build_dmatable(drive, func))) return 1; /* try PIO instead of DMA */ outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ @@ -348,6 +442,9 @@ case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ dma_stat = inb(dma_base+2); return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + case ide_dma_bad_drive: + case ide_dma_good_drive: + return check_drive_lists(drive, (func == ide_dma_good_drive)); default: printk("ide_dmaproc: unsupported func: %d\n", func); return 1; @@ -434,9 +531,29 @@ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; - if (inb(dma_base+2) & 0x80) { - printk("%s: simplex device: DMA disabled\n", name); - dma_base = 0; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_643: + /* + * Lets attempt to use the same Ali tricks + * to fix CMD643..... + */ + case PCI_DEVICE_ID_AL_M5219: + case PCI_DEVICE_ID_AL_M5229: + outb(inb(dma_base+2) & 0x60, dma_base+2); + /* + * Ali 15x3 chipsets know as ALI IV and V report + * this as simplex, skip this test for them. + */ + if (inb(dma_base+2) & 0x80) { + printk("%s: simplex device: DMA forced\n", name); + } + break; + default: + if (inb(dma_base+2) & 0x80) { + printk("%s: simplex device: DMA disabled\n", name); + dma_base = 0; + } } } return dma_base; diff -ur --new-file old/linux/drivers/block/ide-floppy.c new/linux/drivers/block/ide-floppy.c --- old/linux/drivers/block/ide-floppy.c Wed Dec 23 16:54:22 1998 +++ new/linux/drivers/block/ide-floppy.c Thu May 13 20:04:54 1999 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -53,11 +54,6 @@ #include /* - * Main Linux ide driver include file - */ -#include "ide.h" - -/* * The following are used to debug the driver. */ #define IDEFLOPPY_DEBUG_LOG 0 @@ -1011,7 +1007,8 @@ dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); #endif /* CONFIG_BLK_DEV_IDEDMA */ - OUT_BYTE (drive->ctl,IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl,IDE_CONTROL_REG); OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); diff -ur --new-file old/linux/drivers/block/ide-pci.c new/linux/drivers/block/ide-pci.c --- old/linux/drivers/block/ide-pci.c Mon Jan 25 06:54:35 1999 +++ new/linux/drivers/block/ide-pci.c Sat May 15 03:50:32 1999 @@ -1,5 +1,7 @@ /* - * linux/drivers/block/ide-pci.c Version 1.02 December 29, 1997 + * linux/drivers/block/ide-pci.c Version 1.03 May 1, 1999 + * + * Copyright (c) 1998-1999 Andre Hedrick * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -18,26 +20,28 @@ #include #include #include +#include #include #include -#include "ide.h" - #define DEVID_PIIXa ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0}) #define DEVID_PIIXb ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1}) #define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) +#define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262}) #define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) #define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) +#define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE}) #define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640}) +#define DEVID_CMD643 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643}) #define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646}) #define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513}) #define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621}) #define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558}) -#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, 0xd568}) /* from datasheets */ +#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825}) #define DEVID_TRM290 ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290}) #define DEVID_NS87410 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410}) #define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415}) @@ -47,6 +51,10 @@ #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) #define DEVID_HPT343 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) +#define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) +#define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) +#define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) +#define DEVID_CX5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) #define IDE_IGNORE ((void *)-1) @@ -98,11 +106,68 @@ #ifdef CONFIG_BLK_DEV_VIA82C586 extern void ide_init_via82c586(ide_hwif_t *); +extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase); #define INIT_VIA82C586 &ide_init_via82c586 +#define DMA_VIA82C586 &ide_dmacapable_via82c586 #else #define INIT_VIA82C586 NULL +#define DMA_VIA82C586 NULL +#endif + +#ifdef CONFIG_BLK_DEV_ALI15X3 +extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *); +extern void ide_init_ali15x3(ide_hwif_t *); +#define PCI_ALI15X3 &pci_init_ali15x3 +#define INIT_ALI15X3 &ide_init_ali15x3 +#else +#define PCI_ALI15X3 NULL +#define INIT_ALI15X3 NULL +#endif + +#ifdef CONFIG_BLK_DEV_CY82C693 +extern void ide_init_cy82c693(ide_hwif_t *); +#define INIT_CY82C693 &ide_init_cy82c693 +#else +#define INIT_CY82C693 NULL +#endif + +#ifdef CONFIG_BLK_DEV_PDC202XX +extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); +extern void ide_init_pdc202xx(ide_hwif_t *); +#define PCI_PDC202XX &pci_init_pdc202xx +#define INIT_PDC202XX &ide_init_pdc202xx +#else +#define PCI_PDC202XX NULL +#define INIT_PDC202XX NULL +#endif + +#ifdef CONFIG_BLK_DEV_PIIX +extern void ide_init_piix(ide_hwif_t *); +#define INIT_PIIX &ide_init_piix +#else +#define INIT_PIIX NULL +#endif + +#ifdef CONFIG_BLK_DEV_AEC6210 +extern unsigned int pci_init_aec6210(struct pci_dev *, const char *); +#define PCI_AEC6210 &pci_init_aec6210 +#else +#define PCI_AEC6210 NULL +#endif + +#ifdef CONFIG_BLK_DEV_HPT343 +extern unsigned int pci_init_hpt343(struct pci_dev *, const char *); +extern void ide_init_hpt343(ide_hwif_t *); +#define PCI_HPT343 &pci_init_hpt343 +#define INIT_HPT343 &ide_init_hpt343 +#else +#define PCI_HPT343 NULL +#define INIT_HPT343 NULL #endif +#define INIT_SAMURAI NULL +#define INIT_CX5530 NULL + typedef struct ide_pci_enablebit_s { byte reg; /* byte pci reg holding the enable-bit */ byte mask; /* mask to isolate the enable-bit */ @@ -112,36 +177,45 @@ typedef struct ide_pci_device_s { ide_pci_devid_t devid; const char *name; + unsigned int (*init_chipset)(struct pci_dev *dev, const char *name); void (*init_hwif)(ide_hwif_t *hwif); + void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase); ide_pci_enablebit_t enablebits[2]; byte bootable; unsigned int extra; } ide_pci_device_t; static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIXa, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIXb, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_VP_IDE, "VP_IDE", INIT_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, - {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, - {DEVID_RZ1000, "RZ1000", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_RZ1001, "RZ1001", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD640, "CMD640", IDE_IGNORE, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, - {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, - {DEVID_CMD646, "CMD646", INIT_CMD646, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621, "OPTI621", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621X,"OPTI621X", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AEC6210, "AEC6210", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_W82C105, "W82C105", INIT_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_UM8886A, "UM8886A", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886BF,"UM8886BF", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HPT343, "HPT343", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, - {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; + {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_VP_IDE, "VP_IDE", NULL, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, + {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, + {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, + {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, + {DEVID_SIS5513, "SIS5513", NULL, NULL, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, + {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, + {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HPT343, "HPT343", PCI_HPT343, INIT_HPT343, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, + {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0 }, + {DEVID_CY82C693,"CY82C693", NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* * This allows offboard ide-pci cards the enable a BIOS, verify interrupt @@ -151,27 +225,27 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const char *name)) { switch(dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP850UF: - case PCI_DEVICE_ID_PROMISE_20246: - if (dev->rom_address) { - pci_write_config_byte(dev, PCI_ROM_ADDRESS, - dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->rom_address); - } - - if ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID) { - unsigned char irq1 = 0, irq2 = 0; - - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq1); - pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ - if (irq1 != irq2) { - printk("%s: IRQ1 %d IRQ2 %d\n", - name, irq1, irq2); - pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq1); /* 0xbc */ - } - } - return dev->irq; case PCI_DEVICE_ID_TTI_HPT343: + { + int i; + unsigned short pcicmd = 0; + unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + + pci_write_config_byte(dev, 0x80, 0x00); + dev->base_address[0] = (hpt343IoBase + 0x20); + dev->base_address[1] = (hpt343IoBase + 0x34); + dev->base_address[2] = (hpt343IoBase + 0x28); + dev->base_address[3] = (hpt343IoBase + 0x3c); + for(i=0; i<4; i++) + dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; + + pci_read_config_word(dev, PCI_COMMAND, &pcicmd); + if (!(pcicmd & PCI_COMMAND_MEMORY)) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + } + case PCI_DEVICE_ID_PROMISE_20246: + case PCI_DEVICE_ID_PROMISE_20262: + case PCI_DEVICE_ID_ARTOP_ATP850UF: return dev->irq; default: break; @@ -269,7 +343,7 @@ */ for (reg = 0; reg < 4; reg++) if (!dev->base_address[reg]) { - printk("%s: Missing I/O address #%d, please report to \n", name, reg); + printk("%s: Missing I/O address #%d\n", name, reg); return 1; } return 0; @@ -325,7 +399,13 @@ pciirq = dev->irq; if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { printk("%s: not 100%% native mode: will probe irqs later\n", d->name); - pciirq = ide_special_settings(dev, d->name); + /* + * This allows offboard ide-pci cards the enable a BIOS, + * verify interrupt settings of split-mirror pci-config + * space, place chipset into init-mode, and/or preserve + * an interrupt if the card is not native ide support. + */ + pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name); } else if (tried_config) { printk("%s: will probe irqs later\n", d->name); pciirq = 0; @@ -340,6 +420,19 @@ printk("%s: 100%% native mode on irq %d\n", d->name, pciirq); #endif } + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343)) { + /* + * Since there are two cards that report almost identically, + * the only discernable difference is the values + * reported in pcicmd. + * Booting-BIOS card or HPT363 :: pcicmd == 0x07 + * Non-bootable card or HPT343 :: pcicmd == 0x05 + */ + if (pcicmd & PCI_COMMAND_MEMORY) { + printk("%s: is IDE Express HPT363.\n", d->name); + d->bootable = OFF_BOARD; + } + } /* * Set up the IDE ports */ @@ -363,8 +456,8 @@ if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL) continue; /* no room in ide_hwifs[] */ if (hwif->io_ports[IDE_DATA_OFFSET] != base) { - ide_init_hwif_ports(hwif->io_ports, base, NULL); - hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2; + ide_init_hwif_ports(&hwif->hw, base, (ctl + 2), NULL); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; } hwif->chipset = ide_pci; @@ -382,8 +475,10 @@ } } if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF)) + IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF)) { hwif->irq = hwif->channel ? 15 : 14; + goto bypass_umc_dma; + } #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513)) @@ -391,8 +486,12 @@ if (autodma) hwif->autodma = 1; if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || +#ifdef CONFIG_BLK_DEV_HPT343 IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) || +#endif + IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { @@ -406,12 +505,18 @@ dma_base = 0; } } - if (dma_base) - ide_setup_dma(hwif, dma_base, 8); - else + if (dma_base) { + if (d->dma_init) { + d->dma_init(hwif, dma_base); + } else { + ide_setup_dma(hwif, dma_base, 8); + } + } else { printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name); + } } #endif /* CONFIG_BLK_DEV_IDEDMA */ +bypass_umc_dma: if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ d->init_hwif(hwif); mate = hwif; @@ -441,6 +546,8 @@ printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name); else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1)) continue; /* OPTI Viper-M uses same devid for functions 0 and 1 */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) + continue; /* CY82C693 is more than only a IDE controller */ else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n", diff -ur --new-file old/linux/drivers/block/ide-pmac.c new/linux/drivers/block/ide-pmac.c --- old/linux/drivers/block/ide-pmac.c Thu Mar 11 06:48:46 1999 +++ new/linux/drivers/block/ide-pmac.c Thu May 13 20:04:54 1999 @@ -21,6 +21,8 @@ #include #include #include +#include + #include #include #include @@ -31,9 +33,9 @@ #include #include #endif -#include "ide.h" #include "ide_modes.h" +int pmac_ide_ports_known; ide_ioreg_t pmac_ide_regbase[MAX_HWIFS]; int pmac_ide_irq[MAX_HWIFS]; int pmac_ide_count; @@ -58,24 +60,32 @@ * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. */ -void -pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) +void pmac_ide_init_hwif_ports ( hw_regs_t *hw, + ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, + int *irq) { + ide_ioreg_t reg = ide_ioreg_t data_port; int i, r; - *p = 0; - if (base == 0) + if (data_port == 0) return; /* we check only for -EINVAL meaning that we have found a matching bay but with the wrong device type */ - r = check_media_bay_by_base(base, MB_CD); + r = check_media_bay_by_base(data_port, MB_CD); if (r == -EINVAL) return; - for (i = 0; i < 8; ++i) - *p++ = base + i * 0x10; - *p = base + 0x160; + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg * 0x10; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x160; + } if (irq != NULL) { *irq = 0; for (i = 0; i < MAX_HWIFS; ++i) { @@ -104,8 +114,7 @@ } } -__initfunc(void -pmac_ide_probe(void)) +__initfunc(void pmac_ide_probe(void)) { struct device_node *np; int i; @@ -172,7 +181,8 @@ feature_set(np, FEATURE_IDE_enable); hwif = &ide_hwifs[i]; - pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq); + pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_generic; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; hwif->tuneproc = pmac_ide_tuneproc; diff -ur --new-file old/linux/drivers/block/ide-probe.c new/linux/drivers/block/ide-probe.c --- old/linux/drivers/block/ide-probe.c Mon Mar 22 21:44:18 1999 +++ new/linux/drivers/block/ide-probe.c Thu May 13 20:04:54 1999 @@ -18,6 +18,8 @@ * by Andrea Arcangeli * Version 1.03 fix for (hwif->chipset == ide_4drives) * Version 1.04 fixed buggy treatments of known flash memory cards + * fix for (hwif->chipset == ide_pdc4030) + * added ide6/7 */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -35,14 +37,14 @@ #include #include #include +#include + #include #include #include #include -#include "ide.h" - static inline void do_identify (ide_drive_t *drive, byte cmd) { int bswap = 1; @@ -148,17 +150,6 @@ } /* - * Delay for *at least* 50ms. As we don't know how much time is left - * until the next tick occurs, we wait an extra tick to be safe. - * This is used only during the probing/polling for drives at boot time. - */ -static void delay_50ms (void) -{ - unsigned long timeout = jiffies + ((HZ + 19)/20) + 1; - while (0 < (signed long)(timeout - jiffies)); -} - -/* * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive * and waits for a response. It also monitors irqs while this is * happening, in hope of automatically determining which one is @@ -176,20 +167,26 @@ unsigned long irqs = 0; byte s, a; - if (!HWIF(drive)->irq) { /* already got an IRQ? */ - probe_irq_off(probe_irq_on()); /* clear dangling irqs */ - irqs = probe_irq_on(); /* start monitoring irqs */ - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ - } + if (IDE_CONTROL_REG) { + if (!HWIF(drive)->irq) { /* already got an IRQ? */ + probe_irq_off(probe_irq_on()); /* clear dangling irqs */ + irqs = probe_irq_on(); /* start monitoring irqs */ + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ + } - delay_50ms(); /* take a deep breath */ - a = IN_BYTE(IDE_ALTSTATUS_REG); - s = IN_BYTE(IDE_STATUS_REG); - if ((a ^ s) & ~INDEX_STAT) { - printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a); - hd_status = IDE_STATUS_REG; /* ancient Seagate drives, broken interfaces */ - } else - hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ + ide_delay_50ms(); /* take a deep breath */ + a = IN_BYTE(IDE_ALTSTATUS_REG); + s = IN_BYTE(IDE_STATUS_REG); + if ((a ^ s) & ~INDEX_STAT) { + printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a); + hd_status = IDE_STATUS_REG; /* ancient Seagate drives, broken interfaces */ + } else { + hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ + } + } else { + ide_delay_50ms(); + hd_status = IDE_STATUS_REG; + } #if CONFIG_BLK_DEV_PDC4030 if (IS_PDC4030_DRIVE) { @@ -210,10 +207,10 @@ (void) probe_irq_off(irqs); return 1; /* drive timed-out */ } - delay_50ms(); /* give drive a breather */ + ide_delay_50ms(); /* give drive a breather */ } while (IN_BYTE(hd_status) & BUSY_STAT); - delay_50ms(); /* wait for IRQ and DRQ_STAT */ + ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { unsigned long flags; __save_flags(flags); /* local CPU only */ @@ -224,7 +221,7 @@ __restore_flags(flags); /* local CPU only */ } else rc = 2; /* drive refused ID */ - if (!HWIF(drive)->irq) { + if (IDE_CONTROL_REG && !HWIF(drive)->irq) { irqs = probe_irq_off(irqs); /* get our irq number */ if (irqs > 0) { HWIF(drive)->irq = irqs; /* save it for later */ @@ -280,11 +277,11 @@ (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); #endif SELECT_DRIVE(hwif,drive); - delay_50ms(); + ide_delay_50ms(); if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { if (drive->select.b.unit != 0) { SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ - delay_50ms(); /* allow BUSY_STAT to assert & clear */ + ide_delay_50ms(); /* allow BUSY_STAT to assert & clear */ } return 3; /* no i/f present: mmm.. this should be a 4 -ml */ } @@ -297,13 +294,13 @@ if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) { unsigned long timeout; printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT()); - delay_50ms(); + ide_delay_50ms(); OUT_BYTE (drive->select.all, IDE_SELECT_REG); - delay_50ms(); + ide_delay_50ms(); OUT_BYTE(WIN_SRST, IDE_COMMAND_REG); timeout = jiffies; while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE)) - delay_50ms(); + ide_delay_50ms(); rc = try_to_identify(drive, cmd); } if (rc == 1) @@ -314,7 +311,7 @@ } if (drive->select.b.unit != 0) { SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ - delay_50ms(); + ide_delay_50ms(); (void) GET_STAT(); /* ensure drive irq is clear */ } return rc; @@ -407,15 +404,40 @@ unsigned int unit; unsigned long flags; + ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET]; + ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET]; + ide_ioreg_t region_high = region_low; + ide_ioreg_t region_request = 8; + int i; + if (hwif->noprobe) return; if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) probe_cmos_for_drives (hwif); - if ((hwif->chipset != ide_4drives || !hwif->mate->present) + + /* + * Calculate the region that this interface occupies, + * handling interfaces where the registers may not be + * ordered sanely. We deal with the CONTROL register + * separately. + */ + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + if (hwif->io_ports[i]) { + if (hwif->io_ports[i] < region_low) + region_low = hwif->io_ports[i]; + if (hwif->io_ports[i] > region_high) + region_high = hwif->io_ports[i]; + } + } + region_request = (region_high - region_low); + if (region_request == 0x0007) + region_request++; + if ((hwif->chipset != ide_4drives || !hwif->mate->present) && #if CONFIG_BLK_DEV_PDC4030 - && (hwif->chipset != ide_pdc4030 || hwif->channel == 0) + (hwif->chipset != ide_pdc4030 || hwif->channel == 0) && #endif /* CONFIG_BLK_DEV_PDC4030 */ - && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1))) + (ide_check_region(region_low, region_request) || + (ide_control_reg && ide_check_region(ide_control_reg,1)))) { int msgout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { @@ -443,21 +465,22 @@ if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || !hwif->mate->present) { - ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name); - ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); + ide_request_region(region_low, region_request, hwif->name); + if (ide_control_reg) + ide_request_region(ide_control_reg, 1, hwif->name); } } } - if (hwif->reset) { + if (ide_control_reg && hwif->reset) { unsigned long timeout = jiffies + WAIT_WORSTCASE; byte stat; printk("%s: reset\n", hwif->name); - OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]); + OUT_BYTE(12, ide_control_reg); udelay(10); - OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + OUT_BYTE(8, ide_control_reg); do { - delay_50ms(); + ide_delay_50ms(); stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); @@ -660,7 +683,11 @@ max_readahead[hwif->major] = max_ra; for (unit = 0; unit < minors; ++unit) { *bs++ = BLOCK_SIZE; +#ifdef CONFIG_BLK_DEV_PDC4030 + *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : MAX_SECTORS); +#else *max_sect++ = MAX_SECTORS; +#endif *max_ra++ = MAX_READAHEAD; } @@ -693,7 +720,8 @@ if (!hwif->present) return 0; if (!hwif->irq) { - if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { + if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) + { printk("%s: DISABLED, NO IRQ\n", hwif->name); return (hwif->present = 0); } @@ -722,6 +750,12 @@ #endif #if MAX_HWIFS > 5 case IDE5_MAJOR: rfn = &do_ide5_request; break; +#endif +#if MAX_HWIFS > 6 + case IDE6_MAJOR: rfn = &do_ide6_request; break; +#endif +#if MAX_HWIFS > 7 + case IDE7_MAJOR: rfn = &do_ide7_request; break; #endif default: printk("%s: request_fn NOT DEFINED\n", hwif->name); diff -ur --new-file old/linux/drivers/block/ide-proc.c new/linux/drivers/block/ide-proc.c --- old/linux/drivers/block/ide-proc.c Wed May 6 23:42:53 1998 +++ new/linux/drivers/block/ide-proc.c Thu May 13 20:04:54 1999 @@ -65,13 +65,22 @@ #include #include #include +#include + #include -#include "ide.h" #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif +#ifdef CONFIG_BLK_DEV_VIA82C586 +int (*via_display_info)(char *, char **, off_t, int, int) = NULL; +#endif /* CONFIG_BLK_DEV_VIA82C586 */ + +#ifdef CONFIG_BLK_DEV_ALI15X3 +int (*ali_display_info)(char *, char **, off_t, int, int) = NULL; +#endif /* CONFIG_BLK_DEV_ALI15X3 */ + static int ide_getxdigit(char c) { int digit; @@ -682,6 +691,18 @@ ent = create_proc_entry("drivers", 0, root); if (!ent) return; ent->read_proc = proc_ide_read_drivers; +#ifdef CONFIG_BLK_DEV_VIA82C586 + if (via_display_info) { + ent = create_proc_entry("via", 0, root); + ent->get_info = via_display_info; + } +#endif /* CONFIG_BLK_DEV_VIA82C586 */ +#ifdef CONFIG_BLK_DEV_ALI15X3 + if (ali_display_info) { + ent = create_proc_entry("ali", 0, root); + ent->get_info = ali_display_info; + } +#endif /* CONFIG_BLK_DEV_ALI15X3 */ } void proc_ide_destroy(void) @@ -690,6 +711,14 @@ * Mmmm.. does this free up all resources, * or do we need to do a more proper cleanup here ?? */ +#ifdef CONFIG_BLK_DEV_VIA82C586 + if (via_display_info) + remove_proc_entry("ide/via",0); +#endif /* CONFIG_BLK_DEV_VIA82C586 */ +#ifdef CONFIG_BLK_DEV_ALI15X3 + if (ali_display_info) + remove_proc_entry("ide/ali",0); +#endif /* CONFIG_BLK_DEV_ALI15X3 */ remove_proc_entry("ide/drivers", 0); remove_proc_entry("ide", 0); } diff -ur --new-file old/linux/drivers/block/ide-tape.c new/linux/drivers/block/ide-tape.c --- old/linux/drivers/block/ide-tape.c Fri Jan 8 19:04:58 1999 +++ new/linux/drivers/block/ide-tape.c Thu May 13 20:04:54 1999 @@ -338,6 +338,8 @@ #include #include #include +#include +#include #include #include @@ -347,11 +349,6 @@ #include /* - * Main Linux ide driver include file - */ -#include "ide.h" - -/* * For general magnetic tape device compatibility. */ #include @@ -401,6 +398,7 @@ /* * The following are used to debug the driver: * + * Setting IDETAPE_INFO_LOG to 1 will log driver vender information. * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control. * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in * some places. @@ -415,9 +413,15 @@ * is verified to be stable enough. This will make it much more * esthetic. */ +#define IDETAPE_INFO_LOG 0 #define IDETAPE_DEBUG_LOG 0 #define IDETAPE_DEBUG_BUGS 1 +#if IDETAPE_DEBUG_LOG +#undef IDETAPE_INFO_LOG +#define IDETAPE_INFO_LOG IDETAPE_DEBUG_LOG +#endif + /* * After each failed packet command we issue a request sense command * and retry the packet command IDETAPE_MAX_PC_RETRIES times. @@ -1968,7 +1972,8 @@ dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); #endif /* CONFIG_BLK_DEV_IDEDMA */ - OUT_BYTE (drive->ctl,IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl,IDE_CONTROL_REG); OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); @@ -2334,7 +2339,7 @@ */ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); #if IDETAPE_DEBUG_BUGS if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) { @@ -3337,16 +3342,16 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) { struct idetape_id_gcw gcw; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_INFO_LOG unsigned short mask,i; -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_INFO_LOG */ if (!id) return 0; *((unsigned short *) &gcw) = id->config; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_INFO_LOG printk (KERN_INFO "Dumping ATAPI Identify Device tape parameters\n"); printk (KERN_INFO "Protocol Type: "); switch (gcw.protocol) { @@ -3434,7 +3439,7 @@ } else printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n"); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_INFO_LOG */ /* Check that we can support this device */ @@ -3491,7 +3496,7 @@ tape->capabilities = *capabilities; /* Save us a copy */ tape->tape_block_size = capabilities->blk512 ? 512:1024; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_INFO_LOG printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n"); printk (KERN_INFO "Mode Parameter Header:\n"); printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length); @@ -3519,7 +3524,7 @@ printk (KERN_INFO "Continuous transfer limits in blocks - %d\n",capabilities->ctl); printk (KERN_INFO "Current speed in KBps - %d\n",capabilities->speed); printk (KERN_INFO "Buffer size - %d\n",capabilities->buffer_size*512); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_INFO_LOG */ } static void idetape_add_settings(ide_drive_t *drive) @@ -3561,7 +3566,18 @@ drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ - drive->dsc_overlap = 1; +#ifdef CONFIG_BLK_DEV_IDEPCI + /* + * These two ide-pci host adapters appear to need this disabled. + */ + if ((hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || + (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { + drive->dsc_overlap = 0; + } else +#endif /* CONFIG_BLK_DEV_IDEPCI */ + { + drive->dsc_overlap = 1; + } memset (tape, 0, sizeof (idetape_tape_t)); tape->drive = drive; tape->minor = minor; diff -ur --new-file old/linux/drivers/block/ide.c new/linux/drivers/block/ide.c --- old/linux/drivers/block/ide.c Wed May 12 22:19:32 1999 +++ new/linux/drivers/block/ide.c Sun May 16 19:56:16 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.18 August 16, 1998 + * linux/drivers/block/ide.c Version 6.19 January 29, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -92,6 +92,11 @@ * Version 6.16 fixed various bugs; even more SMP friendly * Version 6.17 fix for newest EZ-Drive problem * Version 6.18 default unpartitioned-disk translation now "BIOS LBA" + * Version 6.19 Re-design for a UNIFORM driver for all platforms, + * model based on suggestions from Russell King and + * Geert Uytterhoeven + * Promise DC4030VL now supported. + * delay_50ms() changed to ide_delay_50ms() and exported. * * Some additional driver compile-time options are in ide.h * @@ -99,6 +104,9 @@ * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f */ +#define REVISION "Revision: 6.19" +#define VERSION "Id: ide.c 6.19 1999/01/29" + #undef REALLY_SLOW_IO /* most systems can safely undef this */ #define _IDE_C /* Tell ide.h it's really us */ @@ -114,9 +122,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -124,24 +134,29 @@ #include #include -#include "ide.h" #include "ide_modes.h" #ifdef CONFIG_KMOD #include #endif /* CONFIG_KMOD */ -static const byte ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR }; +#ifdef CONFIG_BLK_DEV_VIA82C586 +extern byte fifoconfig; /* defined in via82c586.c used by ide_setup()*/ +#endif + +static const byte ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR }; static int idebus_parameter; /* holds the "idebus=" parameter */ static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ static int initializing; /* set while initializing built-in drivers */ +#if defined(__mc68000__) || defined(CONFIG_APUS) /* * ide_lock is used by the Atari code to obtain access to the IDE interrupt, * which is shared between several drivers. */ static int ide_lock = 0; +#endif /* __mc68000__ || CONFIG_APUS */ /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. @@ -187,14 +202,18 @@ static void init_hwif_data (unsigned int index) { unsigned int unit; + hw_regs_t hw; ide_hwif_t *hwif = &ide_hwifs[index]; /* bulk initialize hwif & drive info with zeros */ memset(hwif, 0, sizeof(ide_hwif_t)); + memset(&hw, 0, sizeof(hw_regs_t)); /* fill in any non-zero initial values */ hwif->index = index; - ide_init_hwif_ports(hwif->io_ports, ide_default_io_base(index), &hwif->irq); + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq); + memcpy(&hwif->hw, &hw, sizeof(hw)); + memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; #ifdef CONFIG_BLK_DEV_HD if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) @@ -211,6 +230,7 @@ drive->media = ide_disk; drive->select.all = (unit<<4)|0xa0; drive->hwif = hwif; + init_waitqueue_head(&drive->wqueue); drive->ctl = 0x08; drive->ready_stat = READY_STAT; drive->bad_wstat = BAD_W_STAT; @@ -219,6 +239,7 @@ drive->name[0] = 'h'; drive->name[1] = 'd'; drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; + init_waitqueue_head(&drive->wqueue); } } @@ -246,9 +267,13 @@ return; /* already initialized */ magic_cookie = 0; + /* Initialise all interface structures */ for (index = 0; index < MAX_HWIFS; ++index) init_hwif_data(index); + /* Add default hw interfaces */ + ide_init_default_hwifs(); + idebus_parameter = 0; system_bus_speed = 0; } @@ -652,6 +677,10 @@ pre_reset(&hwif->drives[unit]); #if OK_TO_RESET_CONTROLLER + if (!IDE_CONTROL_REG) { + __restore_flags(flags); + return; + } /* * Note that we also set nIEN while resetting the device, * to mask unwanted interrupts from the interface during the reset. @@ -857,7 +886,8 @@ void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { ide_set_handler (drive, handler, WAIT_CMD); - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG); } @@ -1253,6 +1283,20 @@ } #endif /* MAX_HWIFS > 5 */ +#if MAX_HWIFS > 6 +void do_ide6_request (void) +{ + unlock_do_hwgroup_request (ide_hwifs[6].hwgroup); +} +#endif /* MAX_HWIFS > 6 */ + +#if MAX_HWIFS > 7 +void do_ide7_request (void) +{ + unlock_do_hwgroup_request (ide_hwifs[7].hwgroup); +} +#endif /* MAX_HWIFS > 7 */ + static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq) { unsigned long flags; @@ -1370,6 +1414,12 @@ __cli(); /* local CPU only */ spin_lock_irqsave(&hwgroup->spinlock, flags); hwif = hwgroup->hwif; + + if (!ide_ack_intr(hwif)) { + spin_unlock_irqrestore(&hwgroup->spinlock, flags); + return; + } + if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { /* * Not expecting an interrupt from this drive. @@ -1391,7 +1441,6 @@ * Probably not a shared PCI interrupt, * so we can safely try to do something about it: */ - (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); unexpected_intr(irq, hwgroup); } spin_unlock_irqrestore(&hwgroup->spinlock, flags); @@ -1403,7 +1452,6 @@ return; } hwgroup->handler = NULL; - (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); del_timer(&(hwgroup->timer)); spin_unlock_irqrestore(&hwgroup->spinlock, flags); if (drive->unmask) @@ -1490,7 +1538,7 @@ ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned int major = HWIF(drive)->major; struct request *cur_rq; - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); if (IS_PDC4030_DRIVE && rq->buffer != NULL) return -ENOSYS; /* special drive cmds not supported */ @@ -1753,7 +1801,8 @@ * allocated for weird IDE interface chipsets. */ ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); - ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); /* * Remove us from the hwgroup, and free @@ -1817,21 +1866,58 @@ restore_flags(flags); /* all CPUs */ } -int ide_register (int arg1, int arg2, int irq) +/* + * Setup hw_regs_t structure described by parameters. You + * may set up the hw structure yourself OR use this routine to + * do it for you. + */ +void ide_setup_ports ( hw_regs_t *hw, + ide_ioreg_t base, int *offsets, + ide_ioreg_t ctrl, ide_ioreg_t intr, + ide_ack_intr_t *ack_intr, int irq) +{ + int i; + + for (i = 0; i < IDE_NR_PORTS; i++) { + if (offsets[i] == -1) { + switch(i) { + case IDE_CONTROL_OFFSET: + hw->io_ports[i] = ctrl; + break; + case IDE_IRQ_OFFSET: + hw->io_ports[i] = intr; + break; + default: + hw->io_ports[i] = 0; + break; + } + } else { + hw->io_ports[i] = base + offsets[i]; + } + } + hw->irq = irq; + hw->ack_intr = ack_intr; +} + +/* + * Register an IDE interface, specifing exactly the registers etc + * Set init=1 iff calling before probes have taken place. + */ +int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) { int index, retry = 1; ide_hwif_t *hwif; - ide_ioreg_t data_port = (ide_ioreg_t) arg1, ctl_port = (ide_ioreg_t) arg2; do { for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; - if (hwif->io_ports[IDE_DATA_OFFSET] == data_port) + if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET]) goto found; } for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; - if (!hwif->present) + if ((!hwif->present && !initializing) || + (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)) goto found; } for (index = 0; index < MAX_HWIFS; index++) @@ -1843,14 +1929,33 @@ ide_unregister(index); if (hwif->present) return -1; - ide_init_hwif_ports(hwif->io_ports, data_port, &hwif->irq); - if (ctl_port) - hwif->io_ports[IDE_CONTROL_OFFSET] = ctl_port; - hwif->irq = irq; + memcpy(&hwif->hw, hw, sizeof(*hw)); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); + hwif->irq = hw->irq; hwif->noprobe = 0; - ide_init_module(IDE_PROBE_MODULE); - ide_init_module(IDE_DRIVER_MODULE); - return hwif->present ? index : -1; + + if (!initializing) { + ide_init_module(IDE_PROBE_MODULE); + ide_init_module(IDE_DRIVER_MODULE); + } + + if (hwifp) + *hwifp = hwif; + + return (initializing || hwif->present) ? index : -1; +} + +/* + * Compatability function with existing drivers. If you want + * something different, use the function above. + */ +int ide_register (int arg1, int arg2, int irq) +{ + hw_regs_t hw; + + ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL); + hw.irq = irq; + return ide_register_hw(&hw, NULL); } void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) @@ -2075,10 +2180,24 @@ return ide_do_drive_cmd(drive, &rq, ide_wait); } +/* + * Delay for *at least* 50ms. As we don't know how much time is left + * until the next tick occurs, we wait an extra tick to be safe. + * This is used only during the probing/polling for drives at boot time. + * + * However, its usefullness may be needed in other places, thus we export it now. + * The future may change this to a millisecond setable delay. + */ +void ide_delay_50ms (void) +{ + unsigned long timeout = jiffies + ((HZ + 19)/20) + 1; + while (0 < (signed long)(timeout - jiffies)); +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int err, major, minor; + int err = 0, major, minor; ide_drive_t *drive; struct request rq; kdev_t dev; @@ -2114,17 +2233,6 @@ (unsigned long *) &loc->start)) return -EFAULT; return 0; } - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[HWIF(drive)->major] - [minor&PARTN_MASK], - (int *)arg); - - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); @@ -2166,7 +2274,68 @@ return -ENOMEM; memcpy(argbuf, args, 4); } + if ((((byte *)arg)[0] == WIN_SETFEATURES) && + (((byte *)arg)[1] > 66) && + (((byte *)arg)[2] == 3) && + ((drive->id->word93 & 0x2000) == 0)) { + printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); + goto abort; + } err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); + if (!err && + (((byte *)arg)[0] == WIN_SETFEATURES) && + (((byte *)arg)[1] >= 16) && + (((byte *)arg)[2] == 3) && + (drive->id->dma_ultra || + drive->id->dma_mword || + drive->id->dma_1word)) { + + /* + * Re-read drive->id for possible DMA mode + * change (copied from ide-probe.c) + */ + struct hd_driveid *id; + unsigned long timeout, irqs, flags; + + probe_irq_off(probe_irq_on()); + irqs = probe_irq_on(); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + ide_delay_50ms(); + OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG); + timeout = jiffies + WAIT_WORSTCASE; + do { + if (0 < (signed long)(jiffies - timeout)) { + if (irqs) + (void) probe_irq_off(irqs); + goto abort; /* drive timed-out */ + } + ide_delay_50ms(); /* give drive a breather */ + } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); + ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ + if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) + goto abort; + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only; some systems need this */ + id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); + ide_input_data(drive, id, SECTOR_WORDS); + (void) GET_STAT(); /* clear drive IRQ */ + ide__sti(); /* local CPU only */ + __restore_flags(flags); /* local CPU only */ + ide_fix_driveid(id); + if (id && id->cyls) { + drive->id->dma_ultra = id->dma_ultra; + drive->id->dma_mword = id->dma_mword; + drive->id->dma_1word = id->dma_1word; + /* anything more ? */ +#ifdef DEBUG + printk("%s: dma_ultra=%04X, dma_mword=%04X, dma_1word=%04X\n", + drive->name, id->dma_ultra, id->dma_mword, id->dma_1word); +#endif + kfree(id); + } + } + abort: if (copy_to_user((void *)arg, argbuf, argsize)) err = -EFAULT; if (argsize > 4) @@ -2204,7 +2373,12 @@ drive->nice1 = (arg >> IDE_NICE_1) & 1; return 0; - RO_IOCTLS(inode->i_rdev, arg); + case BLKROSET: + case BLKROGET: + case BLKFLSBUF: + case BLKSSZGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); default: if (drive->driver != NULL) @@ -2252,6 +2426,32 @@ } /* + * + */ +char *ide_xfer_verbose (byte xfer_rate) { + switch(xfer_rate) { + case XFER_UDMA_4: return("UDMA 4"); + case XFER_UDMA_3: return("UDMA 3"); + case XFER_UDMA_2: return("UDMA 2"); + case XFER_UDMA_1: return("UDMA 1"); + case XFER_UDMA_0: return("UDMA 0"); + case XFER_MW_DMA_2: return("MW DMA 2"); + case XFER_MW_DMA_1: return("MW DMA 1"); + case XFER_MW_DMA_0: return("MW DMA 0"); + case XFER_SW_DMA_2: return("SW DMA 2"); + case XFER_SW_DMA_1: return("SW DMA 1"); + case XFER_SW_DMA_0: return("SW DMA 0"); + case XFER_PIO_4: return("PIO 4"); + case XFER_PIO_3: return("PIO 3"); + case XFER_PIO_2: return("PIO 2"); + case XFER_PIO_1: return("PIO 1"); + case XFER_PIO_0: return("PIO 0"); + case XFER_PIO_SLOW: return("PIO SLOW"); + default: return("XFER ERROR"); + } +} + +/* * stridx() returns the offset of c within s, * or -1 if c is '\0' or not found within s. */ @@ -2370,7 +2570,22 @@ * "idex=reset" : reset interface before first use * "idex=dma" : enable DMA by default on both drives if possible * - * The following are valid ONLY on ide0, + * "splitfifo=betweenChan" + * : FIFO Configuration of VIA 82c586(,"A"or"B"). + * --see what follows... + * "splitfifo=betweenChan,thresholdprim,thresholdsec" + * : FIFO Configuration of VIA 82c586(,"A" or "B"). + * betweenChan = 1(all FIFO's to primary channel) + * , 2(all FIFO's to secondary channel) + * , 3 or 4(evenly shared between them). + * note: without FIFO, a channel is (u)dma disabled! + * thresholdprim = 4, 3, 2 or 1 + * (standing for 1, 3/4, 1/2, 1/4). + * Sets the threshold of FIFO to begin dma + * transfer on the primary channel. + * thresholdsec = cf upper, but for secondary channel. + * + * The following are valid ONLY on ide0, (except dc4030) * and the defaults for the base,ctl ports must not be altered. * * "ide0=dtc2278" : probe/support DTC2278 interface @@ -2380,6 +2595,7 @@ * "ide0=qd6580" : probe/support qd6580 interface * "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445) * "ide0=umc8672" : probe/support umc8672 chipsets + * "idex=dc4030" : probe/support Promise DC4030VL interface */ __initfunc(void ide_setup (char *s)) { @@ -2391,6 +2607,17 @@ const char max_hwif = '0' + (MAX_HWIFS - 1); printk("ide_setup: %s", s); + +#ifdef CONFIG_BLK_DEV_IDEDOUBLER + if (!strcmp(s, "ide=doubler")) { + extern int ide_doubler; + + printk("ide: Enabled support for IDE doublers\n"); + ide_doubler = 1; + return; + } +#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + init_ide_data (); /* @@ -2454,6 +2681,58 @@ } } +#if defined(CONFIG_BLK_DEV_VIA82C586) + /* + * Look for drive option "splitfifo=..." + */ + + if (s[0] == 's' && s[1] == 'p' && s[2] == 'l' && + s[3] == 'i' && s[4] == 't' && s[5] == 'f' && + s[6] == 'i' && s[7] == 'f' && s[8] == 'o') { + byte tmp = 0x3a; /* default config byte */ + + i = match_parm(&s[9], NULL, vals, 3); + switch(i) { + case 3: + tmp &= 0xf0; + if ((vals[1] > 0) && (vals[1] < 5)) { + /* sets threshold for primary Channel: */ + byte x = 4 - vals[1]; + tmp |= (x << 2); + } + else + goto bad_option; + if ((vals[2] > 0) && (vals[2] < 5)) { + /* sets threshold for secondary Channel: */ + byte x = 4 - vals[2]; + tmp |= x; + } + else + goto bad_option; + case 1: + /* set the FIFO config between channels to 0: */ + tmp &= 0x9f; + /* set the needed FIFO config between channels: */ + if (vals[0] == 1) /* primary fifo only */ + tmp |= 0x10; + else if (vals[0] == 2) /* secondary fifo only */ + tmp |= 0x70; + else if (vals[0] == 4) /* other shared fifo config */ + tmp |= 0x50; + else if (vals[0] == 3) /* default config */ + tmp |= 0x30; + else + goto bad_option; + break; + default: + goto bad_option; + } + /* set the found option in fifoconfig */ + fifoconfig = tmp; + goto done; + } +#endif /* defined(CONFIG_BLK_DEV_VIA82C586) */ + if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e') goto bad_option; /* @@ -2487,9 +2766,9 @@ if (i > 0 || i <= -7) { /* is parameter a chipset name? */ if (hwif->chipset != ide_unknown) goto bad_option; /* chipset already specified */ - if (i <= -7 && hw != 0) + if (i <= -7 && i != -14 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ - if (i <= -7 && ide_hwifs[hw^1].chipset != ide_unknown) + if (i <= -7 && i != -14 && ide_hwifs[hw+1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); } @@ -2593,8 +2872,9 @@ case 2: /* base,ctl */ vals[2] = 0; /* default irq = probe for it */ case 3: /* base,ctl,irq */ - ide_init_hwif_ports(hwif->io_ports, (ide_ioreg_t) vals[0], &hwif->irq); - hwif->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) vals[1]; + hwif->hw.irq = vals[2]; + ide_init_hwif_ports(&hwif->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &hwif->irq); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->irq = vals[2]; hwif->noprobe = 0; hwif->chipset = ide_generic; @@ -2631,9 +2911,11 @@ * an IDE disk drive, or if a geometry was "forced" on the commandline. * Returns 1 if the geometry translation was successful. */ + int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) { ide_drive_t *drive; + static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; const byte *heads = head_vals; unsigned long tracks; @@ -2708,14 +2990,15 @@ printk("[remap +63] "); } } + drive->part[0].nr_sects = current_capacity(drive); printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect); /* * Update the current 3D drive values. */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; + drive->id->cur_cyls = drive->bios_cyl; + drive->id->cur_heads = drive->bios_head; + drive->id->cur_sectors = drive->bios_sect; return 1; } @@ -2758,6 +3041,42 @@ pmac_ide_probe(); } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#ifdef CONFIG_BLK_DEV_IDE_ICSIDE + { + extern void icside_init(void); + icside_init(); + } +#endif /* CONFIG_BLK_DEV_IDE_ICSIDE */ +#ifdef CONFIG_BLK_DEV_IDE_RAPIDE + { + extern void rapide_init(void); + rapide_init(); + } +#endif /* CONFIG_BLK_DEV_IDE_RAPIDE */ +#ifdef CONFIG_BLK_DEV_GAYLE + { + extern void gayle_init(void); + gayle_init(); + } +#endif /* CONFIG_BLK_DEV_GAYLE */ +#ifdef CONFIG_BLK_DEV_FALCON_IDE + { + extern void falconide_init(void); + falconide_init(); + } +#endif /* CONFIG_BLK_DEV_FALCON_IDE */ +#ifdef CONFIG_BLK_DEV_MAC_IDE + { + extern void macide_init(void); + macide_init(); + } +#endif /* CONFIG_BLK_DEV_MAC_IDE */ +#ifdef CONFIG_BLK_DEV_BUDDHA + { + extern void buddha_init(void); + buddha_init(); + } +#endif /* CONFIG_BLK_DEV_BUDDHA */ } __initfunc(void ide_init_builtin_drivers (void)) @@ -3032,6 +3351,12 @@ #if MAX_HWIFS > 5 EXPORT_SYMBOL(do_ide5_request); #endif /* MAX_HWIFS > 5 */ +#if MAX_HWIFS > 6 +EXPORT_SYMBOL(do_ide6_request); +#endif /* MAX_HWIFS > 6 */ +#if MAX_HWIFS > 7 +EXPORT_SYMBOL(do_ide7_request); +#endif /* MAX_HWIFS > 7 */ /* * Driver module @@ -3056,6 +3381,7 @@ EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_wait_cmd); +EXPORT_SYMBOL(ide_delay_50ms); EXPORT_SYMBOL(ide_stall_queue); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(ide_add_proc_entries); @@ -3065,14 +3391,23 @@ EXPORT_SYMBOL(ide_add_setting); EXPORT_SYMBOL(ide_remove_setting); +EXPORT_SYMBOL(ide_register_hw); EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_unregister); +EXPORT_SYMBOL(ide_setup_ports); /* * This is gets invoked once during initialization, to set *everything* up */ __initfunc(int ide_init (void)) { + static char banner_printed = 0; + + if (!banner_printed) { + printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); + banner_printed = 1; + } + init_ide_data (); initializing = 1; diff -ur --new-file old/linux/drivers/block/ide.h new/linux/drivers/block/ide.h --- old/linux/drivers/block/ide.h Tue May 11 19:35:52 1999 +++ new/linux/drivers/block/ide.h Thu Jan 1 01:00:00 1970 @@ -1,769 +0,0 @@ -#ifndef _IDE_H -#define _IDE_H -/* - * linux/drivers/block/ide.h - * - * Copyright (C) 1994-1998 Linus Torvalds & authors - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * This is the multiple IDE interface driver, as evolved from hd.c. - * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15). - * There can be up to two drives per interface, as per the ATA-2 spec. - * - * Primary i/f: ide0: major=3; (hda) minor=0; (hdb) minor=64 - * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64 - * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 - * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 - */ - -/****************************************************************************** - * IDE driver configuration options (play with these as desired): - * - * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary - */ -#undef REALLY_FAST_IO /* define if ide ports are perfect */ -#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */ - -#ifndef SUPPORT_SLOW_DATA_PORTS /* 1 to support slow data ports */ -#define SUPPORT_SLOW_DATA_PORTS 1 /* 0 to reduce kernel size */ -#endif -#ifndef SUPPORT_VLB_SYNC /* 1 to support weird 32-bit chips */ -#define SUPPORT_VLB_SYNC 1 /* 0 to reduce kernel size */ -#endif -#ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */ -#define DISK_RECOVERY_TIME 0 /* for hardware that needs it */ -#endif -#ifndef OK_TO_RESET_CONTROLLER /* 1 needed for good error recovery */ -#define OK_TO_RESET_CONTROLLER 1 /* 0 for use with AH2372A/B interface */ -#endif -#ifndef FAKE_FDISK_FOR_EZDRIVE /* 1 to help linux fdisk with EZDRIVE */ -#define FAKE_FDISK_FOR_EZDRIVE 1 /* 0 to reduce kernel size */ -#endif -#ifndef FANCY_STATUS_DUMPS /* 1 for human-readable drive errors */ -#define FANCY_STATUS_DUMPS 1 /* 0 to reduce kernel size */ -#endif - -#ifdef CONFIG_BLK_DEV_CMD640 -#if 0 /* change to 1 when debugging cmd640 problems */ -void cmd640_dump_regs (void); -#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */ -#endif -#endif /* CONFIG_BLK_DEV_CMD640 */ - -/* - * IDE_DRIVE_CMD is used to implement many features of the hdparm utility - */ -#define IDE_DRIVE_CMD 99 /* (magic) undef to reduce kernel size*/ - -/* - * "No user-serviceable parts" beyond this point :) - *****************************************************************************/ - -typedef unsigned char byte; /* used everywhere */ - -/* - * Probably not wise to fiddle with these - */ -#define ERROR_MAX 8 /* Max read/write errors per sector */ -#define ERROR_RESET 3 /* Reset controller every 4th retry */ -#define ERROR_RECAL 1 /* Recalibrate every 2nd retry */ - -/* - * Ensure that various configuration flags have compatible settings - */ -#ifdef REALLY_SLOW_IO -#undef REALLY_FAST_IO -#endif - -#define HWIF(drive) ((ide_hwif_t *)((drive)->hwif)) -#define HWGROUP(drive) ((ide_hwgroup_t *)(HWIF(drive)->hwgroup)) - -/* - * Definitions for accessing IDE controller registers - */ -#define IDE_NR_PORTS (10) - -#define IDE_DATA_OFFSET (0) -#define IDE_ERROR_OFFSET (1) -#define IDE_NSECTOR_OFFSET (2) -#define IDE_SECTOR_OFFSET (3) -#define IDE_LCYL_OFFSET (4) -#define IDE_HCYL_OFFSET (5) -#define IDE_SELECT_OFFSET (6) -#define IDE_STATUS_OFFSET (7) -#define IDE_CONTROL_OFFSET (8) -#define IDE_IRQ_OFFSET (9) - -#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET -#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -#define IDE_DATA_REG (HWIF(drive)->io_ports[IDE_DATA_OFFSET]) -#define IDE_ERROR_REG (HWIF(drive)->io_ports[IDE_ERROR_OFFSET]) -#define IDE_NSECTOR_REG (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET]) -#define IDE_SECTOR_REG (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET]) -#define IDE_LCYL_REG (HWIF(drive)->io_ports[IDE_LCYL_OFFSET]) -#define IDE_HCYL_REG (HWIF(drive)->io_ports[IDE_HCYL_OFFSET]) -#define IDE_SELECT_REG (HWIF(drive)->io_ports[IDE_SELECT_OFFSET]) -#define IDE_STATUS_REG (HWIF(drive)->io_ports[IDE_STATUS_OFFSET]) -#define IDE_CONTROL_REG (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]) -#define IDE_IRQ_REG (HWIF(drive)->io_ports[IDE_IRQ_OFFSET]) - -#define IDE_FEATURE_REG IDE_ERROR_REG -#define IDE_COMMAND_REG IDE_STATUS_REG -#define IDE_ALTSTATUS_REG IDE_CONTROL_REG -#define IDE_IREASON_REG IDE_NSECTOR_REG -#define IDE_BCOUNTL_REG IDE_LCYL_REG -#define IDE_BCOUNTH_REG IDE_HCYL_REG - -#ifdef REALLY_FAST_IO -#define OUT_BYTE(b,p) outb((b),(p)) -#define IN_BYTE(p) (byte)inb(p) -#else -#define OUT_BYTE(b,p) outb_p((b),(p)) -#define IN_BYTE(p) (byte)inb_p(p) -#endif /* REALLY_FAST_IO */ - -#define GET_ERR() IN_BYTE(IDE_ERROR_REG) -#define GET_STAT() IN_BYTE(IDE_STATUS_REG) -#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) -#define BAD_R_STAT (BUSY_STAT | ERR_STAT) -#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) -#define BAD_STAT (BAD_R_STAT | DRQ_STAT) -#define DRIVE_READY (READY_STAT | SEEK_STAT) -#define DATA_READY (DRQ_STAT) - -/* - * Some more useful definitions - */ -#define IDE_MAJOR_NAME "ide" /* the same for all i/f; see also genhd.c */ -#define MAJOR_NAME IDE_MAJOR_NAME -#define PARTN_BITS 6 /* number of minor dev bits for partitions */ -#define PARTN_MASK ((1< (b2) + (t)) || ((b2) > (b1) + (t))) -#define IDE_MIN(a,b) ((a)<(b) ? (a):(b)) -#define IDE_MAX(a,b) ((a)>(b) ? (a):(b)) - -/* - * Timeouts for various operations: - */ -#define WAIT_DRQ (5*HZ/100) /* 50msec - spec allows up to 20ms */ -#ifdef CONFIG_APM -#define WAIT_READY (5*HZ) /* 5sec - some laptops are very slow */ -#else -#define WAIT_READY (3*HZ/100) /* 30msec - should be instantaneous */ -#endif /* CONFIG_APM */ -#define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?) - if all ATAPI CD is closed at boot */ -#define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ -#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ -#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ - -#define SELECT_DRIVE(hwif,drive) \ -{ \ - if (hwif->selectproc) \ - hwif->selectproc(drive); \ - OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \ -} - -/* - * Now for the data we need to maintain per-drive: ide_drive_t - */ - -#define ide_scsi 0x21 -#define ide_disk 0x20 -#define ide_optical 0x7 -#define ide_cdrom 0x5 -#define ide_tape 0x1 -#define ide_floppy 0x0 - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned set_geometry : 1; /* respecify drive geometry */ - unsigned recalibrate : 1; /* seek to cyl 0 */ - unsigned set_multmode : 1; /* set multmode count */ - unsigned set_tune : 1; /* tune interface for drive */ - unsigned reserved : 4; /* unused */ - } b; - } special_t; - -typedef struct ide_drive_s { - struct request *queue; /* request queue */ - struct ide_drive_s *next; /* circular list of hwgroup drives */ - unsigned long sleep; /* sleep until this time */ - unsigned long service_start; /* time we started last request */ - unsigned long service_time; /* service time of last request */ - special_t special; /* special action flags */ - byte keep_settings; /* restore settings after drive reset */ - byte using_dma; /* disk is using dma for read/write */ - byte waiting_for_dma; /* dma currently in progress */ - byte unmask; /* flag: okay to unmask other irqs */ - byte slow; /* flag: slow data port */ - byte bswap; /* flag: byte swap data */ - byte dsc_overlap; /* flag: DSC overlap */ - byte nice1; /* flag: give potential excess bandwidth */ - unsigned present : 1; /* drive is physically present */ - unsigned noprobe : 1; /* from: hdx=noprobe */ - unsigned busy : 1; /* currently doing revalidate_disk() */ - unsigned removable : 1; /* 1 if need to do check_media_change */ - unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - unsigned no_unmask : 1; /* disallow setting unmask bit */ - unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ - unsigned nobios : 1; /* flag: do not probe bios for drive */ - unsigned revalidate : 1; /* request revalidation */ - unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ - unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ - unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ - unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */ - unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ -#if FAKE_FDISK_FOR_EZDRIVE - unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - byte media; /* disk, cdrom, tape, floppy, ... */ - select_t select; /* basic drive/head select reg value */ - byte ctl; /* "normal" value for IDE_CONTROL_REG */ - byte ready_stat; /* min status value for drive ready */ - byte mult_count; /* current multiple sector setting */ - byte mult_req; /* requested multiple sector setting */ - byte tune_req; /* requested drive tuning setting */ - byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ - byte bad_wstat; /* used for ignoring WRERR_STAT */ - byte nowerr; /* used for ignoring WRERR_STAT */ - byte sect0; /* offset of first sector for DM6:DDO */ - byte usage; /* current "open()" count for drive */ - byte head; /* "real" number of heads */ - byte sect; /* "real" sectors per track */ - byte bios_head; /* BIOS/fdisk/LILO number of heads */ - byte bios_sect; /* BIOS/fdisk/LILO sectors per track */ - unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */ - unsigned short cyl; /* "real" number of cyls */ - unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ - void *hwif; /* actually (ide_hwif_t *) */ - struct wait_queue *wqueue; /* used to wait for drive in open() */ - struct hd_driveid *id; /* drive model identification info */ - struct hd_struct *part; /* drive partition table */ - char name[4]; /* drive name, such as "hda" */ - void *driver; /* (ide_driver_t *) */ - void *driver_data; /* extra driver data */ - struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - void *settings; /* /proc/ide/ drive settings */ - char driver_req[10]; /* requests specific driver */ - } ide_drive_t; - -/* - * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case the caller - * should either try again later, or revert to PIO for the current request. - */ -typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end, - ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly, - ide_dma_test_irq - } ide_dma_action_t; - -typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); - - -/* - * An ide_tuneproc_t() is used to set the speed of an IDE interface - * to a particular PIO mode. The "byte" parameter is used - * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255 - * indicates that the interface driver should "auto-tune" the PIO mode - * according to the drive capabilities in drive->id; - * - * Not all interface types support tuning, and not all of those - * support all possible PIO settings. They may silently ignore - * or round values as they see fit. - */ -typedef void (ide_tuneproc_t)(ide_drive_t *, byte); - -/* - * This is used to provide support for strange interfaces - */ -typedef void (ide_selectproc_t) (ide_drive_t *); - -/* - * hwif_chipset_t is used to keep track of the specific hardware - * chipset used by each IDE interface, if known. - */ -typedef enum { ide_unknown, ide_generic, ide_pci, - ide_cmd640, ide_dtc2278, ide_ali14xx, - ide_qd6580, ide_umc8672, ide_ht6560b, - ide_pdc4030, ide_rz1000, ide_trm290, - ide_cmd646, ide_4drives - } hwif_chipset_t; - -typedef struct ide_pci_devid_s { - unsigned short vid; - unsigned short did; -} ide_pci_devid_t; - -#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0}) -#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did) - -typedef struct hwif_s { - struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ - void *hwgroup; /* actually (ide_hwgroup_t *) */ - ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ - ide_drive_t drives[MAX_DRIVES]; /* drive info */ - struct gendisk *gd; /* gendisk structure */ - ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ - ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ - ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ - unsigned long *dmatable; /* dma physical region descriptor table */ - struct hwif_s *mate; /* other hwif from same PCI chip */ - unsigned long dma_base; /* base addr for dma ports */ - unsigned dma_extra; /* extra addr for dma ports */ - unsigned long config_data; /* for use by chipset-specific code */ - unsigned long select_data; /* for use by chipset-specific code */ - struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - int irq; /* our irq number */ - byte major; /* our major number */ - char name[6]; /* name of interface, eg. "ide0" */ - byte index; /* 0 for ide0; 1 for ide1; ... */ - hwif_chipset_t chipset; /* sub-module for tuning.. */ - unsigned noprobe : 1; /* don't probe for this interface */ - unsigned present : 1; /* this interface exists */ - unsigned serialized : 1; /* serialized operation with mate hwif */ - unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ - unsigned reset : 1; /* reset after probe */ - unsigned autodma : 1; /* automatically try to enable DMA at boot */ - byte channel; /* for dual-port chips: 0=primary, 1=secondary */ - struct pci_dev *pci_dev; /* for pci chipsets */ - ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */ -#if (DISK_RECOVERY_TIME > 0) - unsigned long last_time; /* time when previous rq was done */ -#endif - } ide_hwif_t; - -/* - * internal ide interrupt handler type - */ -typedef void (ide_handler_t)(ide_drive_t *); - -typedef struct hwgroup_s { - spinlock_t spinlock; /* protects "busy" and "handler" */ - ide_handler_t *handler;/* irq handler, if active */ - int busy; /* BOOL: protects all fields below */ - ide_drive_t *drive; /* current drive */ - ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ - struct request *rq; /* current request */ - struct timer_list timer; /* failsafe timer */ - struct request wrq; /* local copy of current write rq */ - unsigned long poll_timeout; /* timeout value during long polls */ - } ide_hwgroup_t; - -/* - * configurable drive settings - */ - -#define TYPE_INT 0 -#define TYPE_INTA 1 -#define TYPE_BYTE 2 -#define TYPE_SHORT 3 - -#define SETTING_READ (1 << 0) -#define SETTING_WRITE (1 << 1) -#define SETTING_RW (SETTING_READ | SETTING_WRITE) - -typedef int (ide_procset_t)(ide_drive_t *, int); -typedef struct ide_settings_s { - char *name; - int rw; - int read_ioctl; - int write_ioctl; - int data_type; - int min; - int max; - int mul_factor; - int div_factor; - void *data; - ide_procset_t *set; - int auto_remove; - struct ide_settings_s *next; -} ide_settings_t; - -void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); -void ide_remove_setting(ide_drive_t *drive, char *name); -ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); -int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); -int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); -void ide_add_generic_settings(ide_drive_t *drive); - -/* - * /proc/ide interface - */ -typedef struct { - const char *name; - mode_t mode; - read_proc_t *read_proc; - write_proc_t *write_proc; -} ide_proc_entry_t; - -#ifdef CONFIG_PROC_FS -void proc_ide_create(void); -void proc_ide_destroy(void); -void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data); -void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p); -read_proc_t proc_ide_read_capacity; -read_proc_t proc_ide_read_geometry; - -/* - * Standard exit stuff: - */ -#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \ -{ \ - len -= off; \ - if (len < count) { \ - *eof = 1; \ - if (len <= 0) \ - return 0; \ - } else \ - len = count; \ - *start = page + off; \ - return len; \ -} -#else -#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0; -#endif - -/* - * Subdrivers support. - */ -#define IDE_SUBDRIVER_VERSION 1 - -typedef int (ide_cleanup_proc)(ide_drive_t *); -typedef void (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long); -typedef void (ide_end_request_proc)(byte, ide_hwgroup_t *); -typedef int (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); -typedef int (ide_open_proc)(struct inode *, struct file *, ide_drive_t *); -typedef void (ide_release_proc)(struct inode *, struct file *, ide_drive_t *); -typedef int (ide_check_media_change_proc)(ide_drive_t *); -typedef void (ide_pre_reset_proc)(ide_drive_t *); -typedef unsigned long (ide_capacity_proc)(ide_drive_t *); -typedef void (ide_special_proc)(ide_drive_t *); -typedef void (ide_setting_proc)(ide_drive_t *); - -typedef struct ide_driver_s { - const char *name; - const char *version; - byte media; - unsigned busy : 1; - unsigned supports_dma : 1; - unsigned supports_dsc_overlap : 1; - ide_cleanup_proc *cleanup; - ide_do_request_proc *do_request; - ide_end_request_proc *end_request; - ide_ioctl_proc *ioctl; - ide_open_proc *open; - ide_release_proc *release; - ide_check_media_change_proc *media_change; - ide_pre_reset_proc *pre_reset; - ide_capacity_proc *capacity; - ide_special_proc *special; - ide_proc_entry_t *proc; - } ide_driver_t; - -#define DRIVER(drive) ((ide_driver_t *)((drive)->driver)) - -/* - * IDE modules. - */ -#define IDE_CHIPSET_MODULE 0 /* not supported yet */ -#define IDE_PROBE_MODULE 1 -#define IDE_DRIVER_MODULE 2 - -typedef int (ide_module_init_proc)(void); - -typedef struct ide_module_s { - int type; - ide_module_init_proc *init; - void *info; - struct ide_module_s *next; -} ide_module_t; - -/* - * ide_hwifs[] is the master data structure used to keep track - * of just about everything in ide.c. Whenever possible, routines - * should be using pointers to a drive (ide_drive_t *) or - * pointers to a hwif (ide_hwif_t *), rather than indexing this - * structure directly (the allocation/layout may change!). - * - */ -#ifndef _IDE_C -extern ide_hwif_t ide_hwifs[]; /* master data repository */ -extern ide_module_t *ide_modules; -#endif - -/* - * We need blk.h, but we replace its end_request by our own version. - */ -#define IDE_DRIVER /* Toggle some magic bits in blk.h */ -#define LOCAL_END_REQUEST /* Don't generate end_request in blk.h */ -#include - -void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); - -/* - * This is used for (nearly) all data transfers from/to the IDE interface - */ -void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); -void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); - -/* - * This is used for (nearly) all ATAPI data transfers from/to the IDE interface - */ -void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); -void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); - -/* - * This is used on exit from the driver, to designate the next irq handler - * and also to start the safety timer. - */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout); - -/* - * Error reporting, in human readable form (luxurious, but a memory hog). - */ -byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat); - -/* - * ide_error() takes action based on the error returned by the controller. - * The calling function must return afterwards, to restart the request. - */ -void ide_error (ide_drive_t *drive, const char *msg, byte stat); - -/* - * Issue a simple drive command - * The drive must be selected beforehand. - */ -void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler); - -/* - * ide_fixstring() cleans up and (optionally) byte-swaps a text string, - * removing leading/trailing blanks and compressing internal blanks. - * It is primarily used to tidy up the model name/number fields as - * returned by the WIN_[P]IDENTIFY commands. - */ -void ide_fixstring (byte *s, const int bytecount, const int byteswap); - -/* - * This routine busy-waits for the drive status to be not "busy". - * It then checks the status for all of the "good" bits and none - * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() -- caller should return. - * - */ -int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout); - -/* - * This routine is called from the partition-table code in genhd.c - * to "convert" a drive to a logical geometry with fewer than 1024 cyls. - * - * The second parameter, "xparm", determines exactly how the translation - * will be handled: - * 0 = convert to CHS with fewer than 1024 cyls - * using the same method as Ontrack DiskManager. - * 1 = same as "0", plus offset everything by 63 sectors. - * -1 = similar to "0", plus redirect sector 0 to sector 1. - * >1 = convert to a CHS geometry with "xparm" heads. - * - * Returns 0 if the translation was not possible, if the device was not - * an IDE disk drive, or if a geometry was "forced" on the commandline. - * Returns 1 if the geometry translation was successful. - */ -int ide_xlate_1024 (kdev_t, int, const char *); - -/* - * Start a reset operation for an IDE interface. - * The caller should return immediately after invoking this. - */ -void ide_do_reset (ide_drive_t *); - -/* - * This function is intended to be used prior to invoking ide_do_drive_cmd(). - */ -void ide_init_drive_cmd (struct request *rq); - -/* - * "action" parameter type for ide_do_drive_cmd() below. - */ -typedef enum - {ide_wait, /* insert rq at end of list, and wait for it */ - ide_next, /* insert rq immediately after current request */ - ide_preempt, /* insert rq in front of current request */ - ide_end} /* insert rq at end of list, but don't wait for it */ - ide_action_t; - -/* - * This function issues a special IDE device request - * onto the request queue. - * - * If action is ide_wait, then the rq is queued at the end of the - * request queue, and the function sleeps until it has been processed. - * This is for use when invoked from an ioctl handler. - * - * If action is ide_preempt, then the rq is queued at the head of - * the request queue, displacing the currently-being-processed - * request and this function returns immediately without waiting - * for the new rq to be completed. This is VERY DANGEROUS, and is - * intended for careful use by the ATAPI tape/cdrom driver code. - * - * If action is ide_next, then the rq is queued immediately after - * the currently-being-processed-request (if any), and the function - * returns without waiting for the new rq to be completed. As above, - * This is VERY DANGEROUS, and is intended for careful use by the - * ATAPI tape/cdrom driver code. - * - * If action is ide_end, then the rq is queued at the end of the - * request queue, and the function returns immediately without waiting - * for the new rq to be completed. This is again intended for careful - * use by the ATAPI tape/cdrom driver code. - */ -int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action); - -/* - * Clean up after success/failure of an explicit drive cmd. - * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). - */ -void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); - -/* - * Issue ATA command and wait for completion. - */ -int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf); - -/* - * ide_system_bus_speed() returns what we think is the system VESA/PCI - * bus speed (in MHz). This is used for calculating interface PIO timings. - * The default is 40 for known PCI systems, 50 otherwise. - * The "idebus=xx" parameter can be used to override this value. - */ -int ide_system_bus_speed (void); - -/* - * ide_multwrite() transfers a block of up to mcount sectors of data - * to a drive as part of a disk multwrite operation. - */ -void ide_multwrite (ide_drive_t *drive, unsigned int mcount); - -/* - * ide_stall_queue() can be used by a drive to give excess bandwidth back - * to the hwgroup by sleeping for timeout jiffies. - */ -void ide_stall_queue (ide_drive_t *drive, unsigned long timeout); - -/* - * ide_get_queue() returns the queue which corresponds to a given device. - */ -struct request **ide_get_queue (kdev_t dev); - -/* - * CompactFlash cards and their brethern pretend to be removable hard disks, - * but they never have a slave unit, and they don't have doorlock mechanisms. - * This test catches them, and is invoked elsewhere when setting appropriate config bits. - */ -int drive_is_flashcard (ide_drive_t *drive); - -int ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags); -void ide_timer_expiry (unsigned long data); -void ide_intr (int irq, void *dev_id, struct pt_regs *regs); -void ide_geninit (struct gendisk *gd); -void do_ide0_request (void); -#if MAX_HWIFS > 1 -void do_ide1_request (void); -#endif -#if MAX_HWIFS > 2 -void do_ide2_request (void); -#endif -#if MAX_HWIFS > 3 -void do_ide3_request (void); -#endif -#if MAX_HWIFS > 4 -void do_ide4_request (void); -#endif -#if MAX_HWIFS > 5 -void do_ide5_request (void); -#endif -void ide_init_subdrivers (void); - -#ifndef _IDE_C -extern struct file_operations ide_fops[]; -#endif - -#ifdef _IDE_C -#ifdef CONFIG_BLK_DEV_IDE -int ideprobe_init (void); -#endif /* CONFIG_BLK_DEV_IDE */ -#ifdef CONFIG_BLK_DEV_IDEDISK -int idedisk_init (void); -#endif /* CONFIG_BLK_DEV_IDEDISK */ -#ifdef CONFIG_BLK_DEV_IDECD -int ide_cdrom_init (void); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE -int idetape_init (void); -#endif /* CONFIG_BLK_DEV_IDETAPE */ -#ifdef CONFIG_BLK_DEV_IDEFLOPPY -int idefloppy_init (void); -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ -#ifdef CONFIG_BLK_DEV_IDESCSI -int idescsi_init (void); -#endif /* CONFIG_BLK_DEV_IDESCSI */ -#endif /* _IDE_C */ - -int ide_register_module (ide_module_t *module); -void ide_unregister_module (ide_module_t *module); -ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n); -int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); -int ide_unregister_subdriver (ide_drive_t *drive); -int ide_replace_subdriver(ide_drive_t *drive, const char *driver); - -#ifdef CONFIG_BLK_DEV_IDEPCI -#define ON_BOARD 1 -#define NEVER_BOARD 0 -#ifdef CONFIG_BLK_DEV_OFFBOARD -# define OFF_BOARD ON_BOARD -#else /* CONFIG_BLK_DEV_OFFBOARD */ -# define OFF_BOARD NEVER_BOARD -#endif /* CONFIG_BLK_DEV_OFFBOARD */ - -unsigned long ide_find_free_region (unsigned short size) __init; -void ide_scan_pcibus (void) __init; -#endif -#ifdef CONFIG_BLK_DEV_IDEDMA -#define BAD_DMA_DRIVE 0 -#define GOOD_DMA_DRIVE 1 -int ide_build_dmatable (ide_drive_t *drive); -void ide_dma_intr (ide_drive_t *drive); -int check_drive_lists (ide_drive_t *drive, int good_bad); -int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); -int ide_release_dma (ide_hwif_t *hwif); -void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; -unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; -#endif - -#ifdef CONFIG_BLK_DEV_PDC4030 -#include "pdc4030.h" -#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030) -#else -#define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ -#endif /* CONFIG_BLK_DEV_PDC4030 */ - -#endif /* _IDE_H */ diff -ur --new-file old/linux/drivers/block/ide_modes.h new/linux/drivers/block/ide_modes.h --- old/linux/drivers/block/ide_modes.h Tue May 11 19:35:44 1999 +++ new/linux/drivers/block/ide_modes.h Sun May 16 22:18:20 1999 @@ -15,7 +15,7 @@ * breaking the fragile cmd640.c support. */ -#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621) || defined(CONFIG_BLK_DEV_IDE_PMAC) +#ifdef CONFIG_BLK_DEV_IDE_MODES /* * Standard (generic) timings for PIO modes, from ATA2 specification. @@ -111,6 +111,8 @@ { "ST3600A", 1 }, { "ST3290A", 0 }, { "ST3144A", 0 }, + { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on */ + /* drive) according to Seagates FIND-ATA program */ { "QUANTUM ELS127A", 0 }, { "QUANTUM ELS170A", 0 }, @@ -222,5 +224,5 @@ } #endif /* _IDE_C */ -#endif /* defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621) */ +#endif /* CONFIG_BLK_DEV_IDE_MODES */ #endif /* _IDE_MODES_H */ diff -ur --new-file old/linux/drivers/block/ll_rw_blk.c new/linux/drivers/block/ll_rw_blk.c --- old/linux/drivers/block/ll_rw_blk.c Fri Mar 12 08:20:14 1999 +++ new/linux/drivers/block/ll_rw_blk.c Tue May 11 23:37:40 1999 @@ -53,7 +53,7 @@ /* * used to wait on when there are no free requests */ -struct wait_queue * wait_for_request = NULL; +DECLARE_WAIT_QUEUE_HEAD(wait_for_request); /* This specifies how many sectors to read ahead on the disk. */ @@ -208,7 +208,7 @@ static struct request * __get_request_wait(int n, kdev_t dev) { register struct request *req; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; add_wait_queue(&wait_for_request, &wait); diff -ur --new-file old/linux/drivers/block/macide.c new/linux/drivers/block/macide.c --- old/linux/drivers/block/macide.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/macide.c Thu May 13 20:04:54 1999 @@ -0,0 +1,167 @@ +/* + * linux/drivers/block/macide.c -- Macintosh IDE Driver + * + * Copyright (C) 1998 by Michael Schmitz + * + * This driver was written based on information obtained from the MacOS IDE + * driver binary by Mikael Forselius + * + * 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 + + /* + * Base of the IDE interface (see ATAManager ROM code) + */ + +#define MAC_HD_BASE 0x50f1a000 + + /* + * Offsets from the above base (scaling 4) + */ + +#define MAC_HD_DATA 0x00 +#define MAC_HD_ERROR 0x04 /* see err-bits */ +#define MAC_HD_NSECTOR 0x08 /* nr of sectors to read/write */ +#define MAC_HD_SECTOR 0x0c /* starting sector */ +#define MAC_HD_LCYL 0x10 /* starting cylinder */ +#define MAC_HD_HCYL 0x14 /* high byte of starting cyl */ +#define MAC_HD_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */ +#define MAC_HD_STATUS 0x1c /* see status-bits */ +#define MAC_HD_CONTROL 0x38 /* control/altstatus */ + +static int macide_offsets[IDE_NR_PORTS] = { + MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL, + MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL +}; + + /* + * Other registers + */ + + /* + * IDE interrupt status register for both (?) hwifs on Quadra + * Initial setting: 0xc + * Guessing again: + * Bit 0+1: some interrupt flags + * Bit 2+3: some interrupt enable + * Bit 4: ?? + * Bit 5: IDE interrupt flag (any hwif) + * Bit 6: maybe IDE interrupt enable (any hwif) ?? + * Bit 7: Any interrupt condition + * + * Only relevant item: bit 5, to be checked by mac_ack_intr + */ + +#define MAC_HD_ISR 0x101 + + /* + * IDE interrupt glue - seems to be wired to Nubus, Slot C? + * (ROM code disassembly again) + * First try: just use Nubus interrupt for Slot C. Have Nubus code call + * a wrapper to ide_intr that checks the ISR (see above). + * Need to #define IDE_IRQ_NUBUS though. + * Alternative method: set a mac_ide_hook function pointer to the wrapper + * here and have via_do_nubus call that hook if set. + * + * Quadra needs the hook, Powerbook can use Nubus slot C. + * Checking the ISR on Quadra is done by mac_ack_intr (see Amiga code). mac_ide_intr + * mac_ide_intr is obsolete except for providing the hwgroup argument. + */ + + /* The Mac hwif data, for passing hwgroup to ide_intr */ +static ide_hwif_t *mac_hwif = NULL; + + /* The function pointer used in the Nubus handler */ +void (*mac_ide_intr_hook)(int, void *, struct pt_regs *) = NULL; + + /* + * Only purpose: feeds the hwgroup to the main IDE handler. + * Obsolete as soon as Nubus code is fixed WRT pseudo slot C int. + * (should be the case on Powerbooks) + * Alas, second purpose: feed correct irq to IDE handler (I know, + * that's cheating) :-((( + * Fix needed for interrupt code: accept Nubus ints in the regular + * request_irq code, then register Powerbook IDE as Nubus slot C, + * Quadra as slot F (F for fictious). + */ +void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + ide_intr(mac_hwif->irq, mac_hwif->hwgroup, regs); +} + + /* + * Check the interrupt status + * + * Note: In 2.0 kernels, there have been timing problems with the + * Powerbook IDE interface (BUSY was asserted too long after the + * interrupt triggered). Result: repeated errors, recalibrate etc. + * Adding a wait loop to read_intr, write_intr and set_geom_intr + * fixed the problem (waits in read/write_intr were present for Amiga + * already). + * Powerbooks were not tested with 2.1 due to lack of FPU emulation + * (thanks Apple for using LC040). If the BUSY problem resurfaces in + * 2.1, my best bet would be to add the wait loop right here, afterr + * checking the interrupt register. + */ + +static int mac_ack_intr(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x20)) + return 0; + return 1; +} + + /* + * Probe for a Macintosh IDE interface + */ + +void macide_init(void) +{ + hw_regs_t hw; + int index = -1; + + if (MACH_IS_MAC) { + switch(macintosh_config->ide_type) { + case 0: + break; + + case MAC_IDE_QUADRA: + ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, + 0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR), + mac_ack_intr, IRQ_MAC_NUBUS); + index = ide_register_hw(&hw, &mac_hwif); + mac_ide_intr_hook = mac_ide_intr; + break; + + default: + ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, + 0, 0, NULL, IRQ_MAC_NUBUS); + index = ide_register_hw(&hw, &mac_hwif); + break; + } + + if (index != -1) { + if (macintosh_config->ide_type == MAC_IDE_QUADRA) + printk("ide%d: Macintosh Quadra IDE interface\n", index); + else + printk("ide%d: Macintosh Powerbook IDE interface\n", index); + } + } +} diff -ur --new-file old/linux/drivers/block/md.c new/linux/drivers/block/md.c --- old/linux/drivers/block/md.c Sat Oct 31 19:37:14 1998 +++ new/linux/drivers/block/md.c Sun May 16 08:43:04 1999 @@ -59,6 +59,7 @@ #define MD_DRIVER #include +#include #include #include #include @@ -98,36 +99,6 @@ int md_thread(void * arg); -static struct gendisk *find_gendisk (kdev_t dev) -{ - struct gendisk *tmp=gendisk_head; - - while (tmp != NULL) - { - if (tmp->major==MAJOR(dev)) - return (tmp); - - tmp=tmp->next; - } - - return (NULL); -} - -char *partition_name (kdev_t dev) -{ - static char name[40]; /* This should be long - enough for a device name ! */ - struct gendisk *hd = find_gendisk (dev); - - if (!hd) - { - sprintf (name, "[dev %s]", kdevname(dev)); - return (name); - } - - return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */ -} - static int legacy_raid_sb (int minor, int pnum) { int i, factor; @@ -653,24 +624,7 @@ return err; break; - case BLKFLSBUF: - fsync_dev (inode->i_rdev); - invalidate_buffers (inode->i_rdev); - break; - - case BLKRASET: - if (arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - err = put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - if (err) - return err; - break; - /* We have a problem here : there is no easy way to give a CHS virtual geometry. We currently pretend that we have a 2 heads 4 sectors (with a BIG number of cylinders...). This drives dosfs @@ -693,7 +647,12 @@ return err; break; - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRAGET: + case BLKRASET: + case BLKFLSBUF: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; @@ -817,12 +776,12 @@ struct md_thread *thread = (struct md_thread *) kmalloc(sizeof(struct md_thread), GFP_KERNEL); int ret; - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); if (!thread) return NULL; memset(thread, 0, sizeof(struct md_thread)); - init_waitqueue(&thread->wqueue); + init_waitqueue_head(&thread->wqueue); thread->sem = &sem; thread->run = run; @@ -838,7 +797,7 @@ void md_unregister_thread (struct md_thread *thread) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); thread->sem = &sem; thread->run = NULL; @@ -901,7 +860,6 @@ EXPORT_SYMBOL(md_maxreadahead); EXPORT_SYMBOL(register_md_personality); EXPORT_SYMBOL(unregister_md_personality); -EXPORT_SYMBOL(partition_name); EXPORT_SYMBOL(md_dev); EXPORT_SYMBOL(md_error); EXPORT_SYMBOL(md_register_thread); diff -ur --new-file old/linux/drivers/block/nbd.c new/linux/drivers/block/nbd.c --- old/linux/drivers/block/nbd.c Wed Mar 10 01:58:05 1999 +++ new/linux/drivers/block/nbd.c Wed May 12 17:41:12 1999 @@ -75,7 +75,7 @@ nbdev = &nbd_dev[dev]; nbd_dev[dev].refcnt++; if (!(nbdev->flags & NBD_INITIALISED)) { - nbdev->queue_lock = MUTEX; + init_MUTEX(&nbdev->queue_lock); nbdev->flags |= NBD_INITIALISED; } MOD_INC_USE_COUNT; diff -ur --new-file old/linux/drivers/block/ns87415.c new/linux/drivers/block/ns87415.c --- old/linux/drivers/block/ns87415.c Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/block/ns87415.c Thu May 13 20:04:54 1999 @@ -17,9 +17,9 @@ #include #include #include -#include -#include "ide.h" +#include +#include static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; diff -ur --new-file old/linux/drivers/block/opti621.c new/linux/drivers/block/opti621.c --- old/linux/drivers/block/opti621.c Tue Jan 5 00:07:27 1999 +++ new/linux/drivers/block/opti621.c Thu May 13 20:04:54 1999 @@ -98,8 +98,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" #define OPTI621_MAX_PIO 3 diff -ur --new-file old/linux/drivers/block/paride/paride.c new/linux/drivers/block/paride/paride.c --- old/linux/drivers/block/paride/paride.c Tue Dec 22 17:29:00 1998 +++ new/linux/drivers/block/paride/paride.c Wed May 12 22:27:37 1999 @@ -247,7 +247,7 @@ pi->pardev = (void *) parport_register_device( pp,pi->device,NULL,pi_wake_up,NULL,0,(void *)pi); - pi->parq = NULL; + init_wait_queue_head(&pi->parq); if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port,pp->name); @@ -357,7 +357,7 @@ pi->parname = NULL; pi->pardev = NULL; - pi->parq = NULL; + init_wait_queue_head(&pi->parq); pi->claimed = 0; pi->claim_cont = NULL; diff -ur --new-file old/linux/drivers/block/paride/paride.h new/linux/drivers/block/paride/paride.h --- old/linux/drivers/block/paride/paride.h Sat Jun 13 21:08:19 1998 +++ new/linux/drivers/block/paride/paride.h Wed May 12 22:27:37 1999 @@ -44,7 +44,7 @@ int reserved; /* number of ports reserved */ int private; /* for protocol module */ - struct wait_queue *parq; /* semaphore for parport sharing */ + wait_queue_head_t parq; /* semaphore for parport sharing */ void *pardev; /* pointer to pardevice */ char *parname; /* parport name */ int claimed; /* parport has already been claimed */ diff -ur --new-file old/linux/drivers/block/paride/pd.c new/linux/drivers/block/paride/pd.c --- old/linux/drivers/block/paride/pd.c Mon Sep 28 19:51:16 1998 +++ new/linux/drivers/block/paride/pd.c Sun May 16 08:43:04 1999 @@ -208,6 +208,7 @@ #define DEVICE_OFF(device) #include +#include #include "pseudo.h" @@ -331,7 +332,7 @@ static int pd_poffs; /* partition offset of current minor */ static char * pd_buf; /* buffer for request in progress */ -static struct wait_queue *pd_wait_open = NULL; +static DECLARE_WAIT_QUEUE_HEAD(pd_wait_open); static char *pd_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR", "READY","BUSY","AMNF","TK0NF","ABRT","MCR", @@ -483,35 +484,23 @@ } put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); - if (err) return (err); - put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg); - return (0); case BLKGETSIZE: if (!arg) return -EINVAL; err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); if (err) return (err); put_user(pd_hd[dev].nr_sects,(long *) arg); return (0); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return pd_revalidate(inode->i_rdev); - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; } diff -ur --new-file old/linux/drivers/block/paride/pf.c new/linux/drivers/block/paride/pf.c --- old/linux/drivers/block/paride/pf.c Wed Nov 4 19:04:43 1998 +++ new/linux/drivers/block/paride/pf.c Sun May 16 08:43:04 1999 @@ -205,6 +205,7 @@ #define DEVICE_OFF(device) #include +#include #include "pseudo.h" @@ -433,31 +434,18 @@ } put_user(0,(long *)&geo->start); return 0; - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); - if (err) return (err); - put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg); - return (0); case BLKGETSIZE: if (!arg) return -EINVAL; err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); if (err) return (err); put_user(PF.capacity,(long *) arg); return (0); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; } diff -ur --new-file old/linux/drivers/block/pdc202xx.c new/linux/drivers/block/pdc202xx.c --- old/linux/drivers/block/pdc202xx.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/pdc202xx.c Thu May 13 20:04:54 1999 @@ -0,0 +1,568 @@ +/* + * linux/drivers/block/pdc202xx.c Version 0.26 May 12, 1999 + * + * Copyright (C) 1998-99 Andre Hedrick + * (hedrick@astro.dyer.vanderbilt.edu) + * + * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this + * compiled into the kernel if you have more than one card installed. + * Note that BIOS v1.29 is reported to fix the problem. Since this is + * safe chipset tuning, including this support is harmless + * + * The latest chipset code will support the following :: + * Three Ultra33 controllers and 12 drives. + * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. + * The 8/4 ratio is a BIOS code limit by promise. + * + * UNLESS you enable "PDC202XX_FORCE_BURST_BIT" + * + * There is only one BIOS in the three contollers. + * + * May 8 20:56:17 Orion kernel: + * Uniform Multi-Platform E-IDE driver Revision: 6.19 + * PDC20246: IDE controller on PCI bus 00 dev a0 + * PDC20246: not 100% native mode: will probe irqs later + * PDC20246: ROM enabled at 0xfebd0000 + * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode. + * ide0: BM-DMA at 0xef80-0xef87, BIOS settings: hda:DMA, hdb:DMA + * ide1: BM-DMA at 0xef88-0xef8f, BIOS settings: hdc:pio, hdd:pio + * PDC20246: IDE controller on PCI bus 00 dev 98 + * PDC20246: not 100% native mode: will probe irqs later + * PDC20246: ROM enabled at 0xfebc0000 + * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode. + * ide2: BM-DMA at 0xef40-0xef47, BIOS settings: hde:DMA, hdf:DMA + * ide3: BM-DMA at 0xef48-0xef4f, BIOS settings: hdg:DMA, hdh:DMA + * PDC20246: IDE controller on PCI bus 00 dev 90 + * PDC20246: not 100% native mode: will probe irqs later + * PDC20246: ROM enabled at 0xfebb0000 + * PDC20246: (U)DMA Burst Bit DISABLED Primary PCI Mode Secondary PCI Mode. + * PDC20246: FORCING BURST BIT 0x00 -> 0x01 ACTIVE + * ide4: BM-DMA at 0xef00-0xef07, BIOS settings: hdi:DMA, hdj:pio + * ide5: BM-DMA at 0xef08-0xef0f, BIOS settings: hdk:pio, hdl:pio + * PIIX3: IDE controller on PCI bus 00 dev 39 + * PIIX3: device not capable of full native PCI mode + * + * ide0 at 0xeff0-0xeff7,0xefe6 on irq 19 + * ide1 at 0xefa8-0xefaf,0xebe6 on irq 19 + * ide2 at 0xefa0-0xefa7,0xef7e on irq 18 + * ide3 at 0xef68-0xef6f,0xef66 on irq 18 + * ide4 at 0xef38-0xef3f,0xef62 on irq 17 + * hda: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=13328/15/63, UDMA(33) + * hdb: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=6256/16/63, UDMA(33) + * hde: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=3893/16/63, DMA + * hdf: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=3158/16/63, DMA + * hdi: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33) + * hdj: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33) + * + * Promise Ultra66 cards with BIOS v1.11 this + * compiled into the kernel if you have more than one card installed. + * + * PDC20262: IDE controller on PCI bus 00 dev a0 + * PDC20262: not 100% native mode: will probe irqs later + * PDC20262: ROM enabled at 0xfebb0000 + * PDC20262: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode. + * ide0: BM-DMA at 0xef00-0xef07, BIOS settings: hda:pio, hdb:pio + * ide1: BM-DMA at 0xef08-0xef0f, BIOS settings: hdc:pio, hdd:pio + * + * UDMA 4/2 and UDMA 3/1 only differ by the testing bit 13 in word93. + * Chipset timing speeds must be identical + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include /* for CONFIG_BLK_DEV_IDEPCI */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PDC202XX_DEBUG_DRIVE_INFO 0 +#define PDC202XX_DECODE_REGISTER_INFO 0 +#define PDC202XX_FORCE_BURST_BIT 0 +#define PDC202XX_FORCE_MASTER_MODE 0 + +extern char *ide_xfer_verbose (byte xfer_rate); + +/* A Register */ +#define SYNC_ERRDY_EN 0xC0 + +#define SYNC_IN 0x80 /* control bit, different for master vs. slave drives */ +#define ERRDY_EN 0x40 /* control bit, different for master vs. slave drives */ +#define IORDY_EN 0x20 /* PIO: IOREADY */ +#define PREFETCH_EN 0x10 /* PIO: PREFETCH */ + +#define PA3 0x08 /* PIO"A" timing */ +#define PA2 0x04 /* PIO"A" timing */ +#define PA1 0x02 /* PIO"A" timing */ +#define PA0 0x01 /* PIO"A" timing */ + +/* B Register */ + +#define MB2 0x80 /* DMA"B" timing */ +#define MB1 0x40 /* DMA"B" timing */ +#define MB0 0x20 /* DMA"B" timing */ + +#define PB4 0x10 /* PIO_FORCE 1:0 */ + +#define PB3 0x08 /* PIO"B" timing */ /* PIO flow Control mode */ +#define PB2 0x04 /* PIO"B" timing */ /* PIO 4 */ +#define PB1 0x02 /* PIO"B" timing */ /* PIO 3 half */ +#define PB0 0x01 /* PIO"B" timing */ /* PIO 3 other half */ + +/* C Register */ +#define IORDYp_NO_SPEED 0x4F +#define SPEED_DIS 0x0F + +#define DMARQp 0x80 +#define IORDYp 0x40 +#define DMAR_EN 0x20 +#define DMAW_EN 0x10 + +#define MC3 0x08 /* DMA"C" timing */ +#define MC2 0x04 /* DMA"C" timing */ +#define MC1 0x02 /* DMA"C" timing */ +#define MC0 0x01 /* DMA"C" timing */ + +#if PDC202XX_DECODE_REGISTER_INFO + +#define REG_A 0x01 +#define REG_B 0x02 +#define REG_C 0x04 +#define REG_D 0x08 + +static void decode_registers (byte registers, byte value) +{ + byte bit = 0, bit1 = 0, bit2 = 0; + + switch(registers) { + case REG_A: + bit2 = 0; + printk("A Register "); + if (value & 0x80) printk("SYNC_IN "); + if (value & 0x40) printk("ERRDY_EN "); + if (value & 0x20) printk("IORDY_EN "); + if (value & 0x10) printk("PREFETCH_EN "); + if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; } + if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; } + if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; } + if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; } + printk("PIO(A) = %d ", bit2); + break; + case REG_B: + bit1 = 0;bit2 = 0; + printk("B Register "); + if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; } + if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; } + if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; } + printk("DMA(B) = %d ", bit1 >> 5); + if (value & 0x10) printk("PIO_FORCED/PB4 "); + if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; } + if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; } + if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; } + if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; } + printk("PIO(B) = %d ", bit2); + break; + case REG_C: + bit2 = 0; + printk("C Register "); + if (value & 0x80) printk("DMARQp "); + if (value & 0x40) printk("IORDYp "); + if (value & 0x20) printk("DMAR_EN "); + if (value & 0x10) printk("DMAW_EN "); + + if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; } + if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; } + if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; } + if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; } + printk("DMA(C) = %d ", bit2); + break; + case REG_D: + printk("D Register "); + break; + default: + return; + } + printk("\n %s ", (registers & REG_D) ? "DP" : + (registers & REG_C) ? "CP" : + (registers & REG_B) ? "BP" : + (registers & REG_A) ? "AP" : "ERROR"); + for (bit=128;bit>0;bit/=2) + printk("%s", (value & bit) ? "1" : "0"); + printk("\n"); +} + +#endif /* PDC202XX_DECODE_REGISTER_INFO */ + +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + int err; + unsigned int drive_conf; + byte drive_pci; + byte test1, test2, speed; + byte AP, BP, CP, DP, EP; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + byte udma_66 = ((id->word93 & 0x2000) && (dev->device == PCI_DEVICE_ID_PROMISE_20262)) ? 1 : 0; + byte udma_33 = ultra ? (inb((dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0; + + pci_read_config_byte(dev, 0x50, &EP); + + switch(drive_number) { + case 0: drive_pci = 0x60; + pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; + pci_read_config_byte(dev, (drive_pci), &test1); + if (!(test1 & SYNC_ERRDY_EN)) + pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); + break; + case 1: drive_pci = 0x64; + pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; + pci_read_config_byte(dev, 0x60, &test1); + pci_read_config_byte(dev, (drive_pci), &test2); + if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) + pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); + break; + case 2: drive_pci = 0x68; + pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; + pci_read_config_byte(dev, (drive_pci), &test1); + if (!(test1 & SYNC_ERRDY_EN)) + pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); + break; + case 3: drive_pci = 0x6c; + pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; + pci_read_config_byte(dev, 0x68, &test1); + pci_read_config_byte(dev, (drive_pci), &test2); + if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) + pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); + break; + default: + return ide_dma_off; + } + + if (drive->media != ide_disk) + return ide_dma_off_quietly; + + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + pci_read_config_byte(dev, (drive_pci)|0x03, &DP); + + if (id->capability & 4) { /* IORDY_EN */ + pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); + pci_read_config_byte(dev, (drive_pci), &AP); + } + + if (drive->media == ide_disk) { /* PREFETCH_EN */ + pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); + pci_read_config_byte(dev, (drive_pci), &AP); + } + + if ((BP & 0xF0) && (CP & 0x0F)) { + /* clear DMA modes of upper 842 bits of B Register */ + /* clear PIO forced mode upper 1 bit of B Register */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + + /* clear DMA modes of lower 8421 bits of C Register */ + pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + } + + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + + if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { + if (!((id->dma_ultra >> 8) & 16)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x1010; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 8 == UDMA mode 4 == speed 6 plus cable */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01); + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { + if (!((id->dma_ultra >> 8) & 8)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0808; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 7 == UDMA mode 3 == speed 5 plus cable */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02); + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && (udma_33)) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 6 == UDMA mode 2 */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01); + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (udma_33)) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 5 == UDMA mode 1 */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02); + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (udma_33)) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 4 == UDMA mode 0 */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03); + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 4 == DMA mode 2 multi-word */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03); + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 3 == DMA mode 1 multi-word */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x04); + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + /* speed 2 == DMA mode 0 multi-word */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05); + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + } + /* speed 2 == DMA mode 2 single-word */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05); + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + } + /* speed 1 == DMA mode 1 single-word */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x80); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x06); + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + } + /* speed 0 == DMA mode 0 single-word */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP|0xC0); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x0B); + speed = XFER_SW_DMA_0; + } else { + /* restore original pci-config space */ + pci_write_config_dword(dev, drive_pci, drive_conf); + return ide_dma_off_quietly; + } + + err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + +#if PDC202XX_DECODE_REGISTER_INFO + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + + decode_registers(REG_A, AP); + decode_registers(REG_B, BP); + decode_registers(REG_C, CP); + decode_registers(REG_D, DP); +#endif /* PDC202XX_DECODE_REGISTER_INFO */ + +#if PDC202XX_DEBUG_DRIVE_INFO + printk("%s: %s drive%d 0x%08x ", + drive->name, ide_xfer_verbose(speed), + drive_number, drive_conf); + pci_read_config_dword(dev, drive_pci, &drive_conf); + printk("0x%08x\n", drive_conf); +#endif /* PDC202XX_DEBUG_DRIVE_INFO */ + +chipset_is_set: + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +/* 0 1 2 3 4 5 6 7 8 + * 960, 480, 390, 300, 240, 180, 120, 90, 60 + * 180, 150, 120, 90, 60 + * DMA_Speed + * 180, 120, 90, 90, 90, 60, 30 + * 11, 5, 4, 3, 2, 1, 0 + */ + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + ide_dma_action_t dma_func = ide_dma_off_quietly; + + if (id && (id->capability & 1) && hwif->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + return HWIF(drive)->dmaproc(ide_dma_off, drive); + } + + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, 1); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0004) || + (id->dma_1word & 0x0004)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, 0); + } + } else if ((ide_dmaproc(ide_dma_good_drive, drive)) && + (id->eide_dma_time > 150)) { + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, 0); + } + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ +int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +__initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name)) +{ + unsigned long high_16 = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + byte udma_speed_flag = inb(high_16 + 0x001f); + byte primary_mode = inb(high_16 + 0x001a); + byte secondary_mode = inb(high_16 + 0x001b); + + if (dev->rom_address) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address); + } + + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { + byte irq = 0, irq2 = 0; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ + if (irq != irq2) { + pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ + printk("%s: pci-config space interrupt mirror fixed.\n", name); + } + } + + printk("%s: (U)DMA Burst Bit %sABLED " \ + "Primary %s Mode " \ + "Secondary %s Mode.\n", + name, + (udma_speed_flag & 1) ? "EN" : "DIS", + (primary_mode & 1) ? "MASTER" : "PCI", + (secondary_mode & 1) ? "MASTER" : "PCI" ); + +#if PDC202XX_FORCE_BURST_BIT + if (!(udma_speed_flag & 1)) { + printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); + outb(udma_speed_flag|1, high_16 + 0x001f); + printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); + } +#endif /* PDC202XX_FORCE_BURST_BIT */ + +#if PDC202XX_FORCE_MASTER_MODE + if (!(primary_mode & 1)) { + printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", + name, primary_mode, (primary_mode|1)); + outb(primary_mode|1, high_16 + 0x001a); + printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); + } + + if (!(secondary_mode & 1)) { + printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ", + name, secondary_mode, (secondary_mode|1)); + outb(secondary_mode|1, high_16 + 0x001b); + printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); + } +#endif /* PDC202XX_FORCE_MASTER_MODE */ + return dev->irq; +} + +__initfunc(void ide_init_pdc202xx (ide_hwif_t *hwif)) +{ + if (hwif->dma_base) { + hwif->dmaproc = &pdc202xx_dmaproc; + } +} diff -ur --new-file old/linux/drivers/block/pdc4030.c new/linux/drivers/block/pdc4030.c --- old/linux/drivers/block/pdc4030.c Tue Dec 29 20:24:57 1998 +++ new/linux/drivers/block/pdc4030.c Thu May 13 20:04:54 1999 @@ -1,17 +1,18 @@ /* -*- linux-c -*- - * linux/drivers/block/pdc4030.c Version 0.08 Nov 30, 1997 + * linux/drivers/block/pdc4030.c Version 0.10 Jan 25, 1999 * - * Copyright (C) 1995-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1995-1999 Linus Torvalds & authors (see below) */ /* * Principal Author/Maintainer: peterd@pnd-pc.demon.co.uk * * This file provides support for the second port and cache of Promise - * IDE interfaces, e.g. DC4030, DC5030. + * IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2. * * Thanks are due to Mark Lord for advice and patiently answering stupid - * questions, and all those mugs^H^H^H^Hbrave souls who've tested this. + * questions, and all those mugs^H^H^H^Hbrave souls who've tested this, + * especially Andre Hedrick. * * Version 0.01 Initial version, #include'd in ide.c rather than * compiled separately. @@ -29,6 +30,9 @@ * Version 0.07 Added support for DC4030 variants * Secondary interface autodetection * Version 0.08 Renamed to pdc4030.c + * Version 0.09 Obsolete - never released - did manual write request + * splitting before max_sectors[major][minor] available. + * Version 0.10 Updated for 2.1 series of kernels */ /* @@ -37,12 +41,17 @@ * * 'linux ide0=dc4030' * - * As before, it seems that somewhere around 3Megs when writing, bad things - * start to happen [timeouts/retries -ml]. If anyone can give me more feedback, - * I'd really appreciate it. [email: peterd@pnd-pc.demon.co.uk] + * It should now work as a second controller also ('ide1=dc4030') but only + * if you DON'T have BIOS V4.44, which has a bug. If you have this and EPROM + * programming facilities, I can tell you what to fix... * + * As of January 1999, Promise Technology Inc. have finally supplied me with + * some technical information which has shed a glimmer of light on some of the + * problems I was having, especially with writes. */ +#define DEBUG_READ +#define DEBUG_WRITE #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -54,9 +63,11 @@ #include #include #include +#include + #include #include -#include "ide.h" + #include "pdc4030.h" /* This is needed as the controller may not interrupt if the required data is @@ -124,40 +135,48 @@ { ide_hwif_t *hwif = hwif_required; ide_drive_t *drive; - ide_hwif_t *second_hwif; + ide_hwif_t *hwif2; struct dc_ident ident; int i; if (!hwif) return 0; drive = &hwif->drives[0]; - second_hwif = &ide_hwifs[hwif->index+1]; - if(hwif->chipset == ide_pdc4030) /* we've already been found ! */ - return 1; - - if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) - { - return 0; + hwif2 = &ide_hwifs[hwif->index+1]; + if (hwif->chipset == ide_pdc4030) /* we've already been found ! */ + return 1; + + if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) { + return 0; } OUT_BYTE(0x08,IDE_CONTROL_REG); - if(pdc4030_cmd(drive,PROMISE_GET_CONFIG)) { - return 0; + if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) { + return 0; } - if(ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) { - printk("%s: Failed Promise read config!\n",hwif->name); - return 0; + if (ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) { + printk(KERN_INFO + "%s: Failed Promise read config!\n",hwif->name); + return 0; } ide_input_data(drive,&ident,SECTOR_WORDS); - if(ident.id[1] != 'P' || ident.id[0] != 'T') { - return 0; + if (ident.id[1] != 'P' || ident.id[0] != 'T') { + return 0; } - printk("%s: Promise caching controller, ",hwif->name); + printk(KERN_INFO "%s: Promise caching controller, ",hwif->name); switch(ident.type) { - case 0x43: printk("DC4030VL-2, "); break; - case 0x41: printk("DC4030VL-1, "); break; - case 0x40: printk("DC4030VL, "); break; - default: printk("unknown - type 0x%02x - please report!\n" + case 0x43: printk("DC4030VL-2, "); break; + case 0x41: printk("DC4030VL-1, "); break; + case 0x40: printk("DC4030VL, "); break; + default: + printk("unknown - type 0x%02x - please report!\n" ,ident.type); + printk("Please e-mail the following data to " + "promise@pnd-pc.demon.co.uk along with\n" + "a description of your card and drives:\n"); + for (i=0; i < 0x90; i++) { + printk("%02x ", ((unsigned char *)&ident)[i]); + if ((i & 0x0f) == 0x0f) printk("\n"); + } return 0; } printk("%dKB cache, ",(int)ident.cache_mem); @@ -167,27 +186,35 @@ default: hwif->irq = 15; break; } printk("on IRQ %d\n",hwif->irq); - hwif->chipset = second_hwif->chipset = ide_pdc4030; - hwif->mate = second_hwif; - second_hwif->mate = hwif; - second_hwif->channel = 1; - hwif->selectproc = second_hwif->selectproc = &promise_selectproc; + hwif->chipset = hwif2->chipset = ide_pdc4030; + hwif->mate = hwif2; + hwif2->mate = hwif; + hwif2->channel = 1; + hwif->selectproc = hwif2->selectproc = &promise_selectproc; /* Shift the remaining interfaces down by one */ for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) { ide_hwif_t *h = &ide_hwifs[i]; - printk("Shifting i/f %d values to i/f %d\n",i-1,i); - ide_init_hwif_ports(h->io_ports, (h-1)->io_ports[IDE_DATA_OFFSET], NULL); - h->io_ports[IDE_CONTROL_OFFSET] = (h-1)->io_ports[IDE_CONTROL_OFFSET]; +#ifdef DEBUG + printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i); +#endif + ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL); + memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports)); h->noprobe = (h-1)->noprobe; } - ide_init_hwif_ports(second_hwif->io_ports, hwif->io_ports[IDE_DATA_OFFSET], NULL); - second_hwif->io_ports[IDE_CONTROL_OFFSET] = hwif->io_ports[IDE_CONTROL_OFFSET]; - second_hwif->irq = hwif->irq; + ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL); + memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports)); + hwif2->irq = hwif->irq; + hwif2->hw.irq = hwif->hw.irq = hwif->irq; for (i=0; i<2 ; i++) { - hwif->drives[i].io_32bit = 3; - second_hwif->drives[i].io_32bit = 3; - if(!ident.current_tm[i+2].cyl) second_hwif->drives[i].noprobe=1; + hwif->drives[i].io_32bit = 3; + hwif2->drives[i].io_32bit = 3; + hwif->drives[i].keep_settings = 1; + hwif2->drives[i].keep_settings = 1; + if (!ident.current_tm[i].cyl) + hwif->drives[i].noprobe = 1; + if (!ident.current_tm[i+2].cyl) + hwif2->drives[i].noprobe = 1; } return 1; } @@ -198,7 +225,7 @@ static void promise_read_intr (ide_drive_t *drive) { byte stat; - int i; + int total_remaining; unsigned int sectors_left, sectors_avail, nsect; struct request *rq; @@ -209,99 +236,140 @@ read_again: do { - sectors_left = IN_BYTE(IDE_NSECTOR_REG); - IN_BYTE(IDE_SECTOR_REG); + sectors_left = IN_BYTE(IDE_NSECTOR_REG); + IN_BYTE(IDE_SECTOR_REG); } while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left); rq = HWGROUP(drive)->rq; sectors_avail = rq->nr_sectors - sectors_left; + if (!sectors_avail) + goto read_again; read_next: rq = HWGROUP(drive)->rq; - if ((nsect = rq->current_nr_sectors) > sectors_avail) + nsect = rq->current_nr_sectors; + if (nsect > sectors_avail) nsect = sectors_avail; sectors_avail -= nsect; ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); -#ifdef DEBUG - printk("%s: promise_read: sectors(%ld-%ld), buffer=0x%08lx, " - "remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, - (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); +#ifdef DEBUG_READ + printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), " + "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector, + rq->sector+nsect-1, (unsigned long) rq->buffer, + rq->nr_sectors-nsect); #endif rq->sector += nsect; rq->buffer += nsect<<9; rq->errors = 0; - i = (rq->nr_sectors -= nsect); - if ((rq->current_nr_sectors -= nsect) <= 0) + rq->nr_sectors -= nsect; + total_remaining = rq->nr_sectors; + if ((rq->current_nr_sectors -= nsect) <= 0) { ide_end_request(1, HWGROUP(drive)); - if (i > 0) { + } +/* + * Now the data has been read in, do the following: + * + * if there are still sectors left in the request, + * if we know there are still sectors available from the interface, + * go back and read the next bit of the request. + * else if DRQ is asserted, there are more sectors available, so + * go back and find out how many, then read them in. + * else if BUSY is asserted, we are going to get an interrupt, so + * set the handler for the interrupt and just return + */ + if (total_remaining > 0) { if (sectors_avail) - goto read_next; + goto read_next; stat = GET_STAT(); - if(stat & DRQ_STAT) - goto read_again; - if(stat & BUSY_STAT) { - ide_set_handler (drive, &promise_read_intr, WAIT_CMD); - return; + if (stat & DRQ_STAT) + goto read_again; + if (stat & BUSY_STAT) { +#ifdef DEBUG_READ + printk(KERN_DEBUG "%s: promise_read: waiting for" + "interrupt\n", drive->name); +#endif + ide_set_handler (drive, &promise_read_intr, WAIT_CMD); + return; } - printk("Ah! promise read intr: sectors left !DRQ !BUSY\n"); + printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left " + "!DRQ !BUSY\n", drive->name); ide_error(drive, "promise read intr", stat); } } /* + * promise_write_intr() + * This interrupt is called after the particularly odd polling for completion + * of the write request, once all the data has been sent. + */ +static void promise_write_intr(ide_drive_t *drive) +{ + byte stat; + int i; + struct request *rq; + + if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { + ide_error(drive, "promise_write_intr", stat); + } + +#ifdef DEBUG_WRITE + printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); +#endif + rq = HWGROUP(drive)->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, HWGROUP(drive)); + } +} + +/* * promise_write_pollfunc() is the handler for disk write completion polling. */ static void promise_write_pollfunc (ide_drive_t *drive) { - int i; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq; + if (IN_BYTE(IDE_NSECTOR_REG) != 0) { + if (time_before(jiffies, HWGROUP(drive)->poll_timeout)) { + ide_set_handler (drive, &promise_write_pollfunc, 1); + return; /* continue polling... */ + } + printk(KERN_ERR "%s: write timed-out!\n",drive->name); + ide_error (drive, "write timeout", GET_STAT()); + return; + } - if (IN_BYTE(IDE_NSECTOR_REG) != 0) { - if (time_before(jiffies, hwgroup->poll_timeout)) { - ide_set_handler (drive, &promise_write_pollfunc, 1); - return; /* continue polling... */ - } - printk("%s: write timed-out!\n",drive->name); - ide_error (drive, "write timeout", GET_STAT()); - return; - } - +#ifdef DEBUG_WRITE + printk(KERN_DEBUG "%s: Doing last 4 sectors\n", drive->name); +#endif ide_multwrite(drive, 4); - rq = hwgroup->rq; - for (i = rq->nr_sectors; i > 0;) { - i -= rq->current_nr_sectors; - ide_end_request(1, hwgroup); - } - return; + ide_set_handler(drive, &promise_write_intr, WAIT_CMD); + return; } /* * promise_write() transfers a block of one or more sectors of data to a * drive as part of a disk write operation. All but 4 sectors are transfered * in the first attempt, then the interface is polled (nicely!) for completion - * before the final 4 sectors are transfered. Don't ask me why, but this is - * how it's done in the drivers for other O/Ses. There is no interrupt - * generated on writes, which is why we have to do it like this. + * before the final 4 sectors are transfered. The interrupt generated on + * writes occurs after this process, which is why I got it wrong for so long! */ static void promise_write (ide_drive_t *drive) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq = &hwgroup->wrq; - int i; - - if (rq->nr_sectors > 4) { - ide_multwrite(drive, rq->nr_sectors - 4); - hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &promise_write_pollfunc, 1); - return; - } else { - ide_multwrite(drive, rq->nr_sectors); - rq = hwgroup->rq; - for (i = rq->nr_sectors; i > 0;) { - i -= rq->current_nr_sectors; - ide_end_request(1, hwgroup); - } - } + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = &hwgroup->wrq; + +#ifdef DEBUG_WRITE + printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), " + "buffer=0x%08lx\n", drive->name, rq->sector, + rq->sector + rq->nr_sectors - 1, rq->buffer); +#endif + if (rq->nr_sectors > 4) { + ide_multwrite(drive, rq->nr_sectors - 4); + hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + ide_set_handler (drive, &promise_write_pollfunc, 1); + return; + } else { + ide_multwrite(drive, rq->nr_sectors); + ide_set_handler(drive, &promise_write_intr, WAIT_CMD); + } } /* @@ -315,43 +383,54 @@ byte stat; if (rq->cmd == READ) { - ide_set_handler(drive, &promise_read_intr, WAIT_CMD); - OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); -/* The card's behaviour is odd at this point. If the data is - available, DRQ will be true, and no interrupt will be - generated by the card. If this is the case, we need to simulate - an interrupt. Ugh! Otherwise, if an interrupt will occur, bit0 - of the SELECT register will be high, so we can just return and - be interrupted.*/ - timeout = jiffies + HZ/20; /* 50ms wait */ - do { - stat=GET_STAT(); - if(stat & DRQ_STAT) { - disable_irq(HWIF(drive)->irq); - ide_intr(HWIF(drive)->irq,HWGROUP(drive),NULL); - enable_irq(HWIF(drive)->irq); - return; - } - if(IN_BYTE(IDE_SELECT_REG) & 0x01) - return; - udelay(1); - } while (time_before(jiffies, timeout)); - printk("%s: reading: No DRQ and not waiting - Odd!\n", - drive->name); - return; - } - if (rq->cmd == WRITE) { - OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); - if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk("%s: no DRQ after issuing PROMISE_WRITE\n", drive->name); - return; - } - if (!drive->unmask) - __cli(); /* local CPU only */ - HWGROUP(drive)->wrq = *rq; /* scratchpad */ - promise_write(drive); - return; + OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); +/* + * The card's behaviour is odd at this point. If the data is + * available, DRQ will be true, and no interrupt will be + * generated by the card. If this is the case, we need to call the + * "interrupt" handler (promise_read_intr) directly. Otherwise, if + * an interrupt is going to occur, bit0 of the SELECT register will + * be high, so we can set the handler the just return and be interrupted. + * If neither of these is the case, we wait for up to 50ms (badly I'm + * afraid!) until one of them is. + */ + timeout = jiffies + HZ/20; /* 50ms wait */ + do { + stat=GET_STAT(); + if (stat & DRQ_STAT) { + udelay(1); + promise_read_intr(drive); + return; + } + if (IN_BYTE(IDE_SELECT_REG) & 0x01) { +#ifdef DEBUG_READ + printk(KERN_DEBUG "%s: read: waiting for " + "interrupt\n", drive->name); +#endif + ide_set_handler(drive, &promise_read_intr, WAIT_CMD); + return; + } + udelay(1); + } while (time_before(jiffies, timeout)); + + printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", + drive->name); + + } else if (rq->cmd == WRITE) { + OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); + if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing " + "PROMISE_WRITE\n", drive->name); + return; + } + if (!drive->unmask) + __cli(); /* local CPU only */ + HWGROUP(drive)->wrq = *rq; /* scratchpad */ + promise_write(drive); + + } else { + printk("KERN_WARNING %s: bad command: %d\n", + drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); } - printk("%s: bad command: %d\n", drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); } diff -ur --new-file old/linux/drivers/block/piix.c new/linux/drivers/block/piix.c --- old/linux/drivers/block/piix.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/piix.c Thu May 13 20:04:54 1999 @@ -0,0 +1,258 @@ +/* + * linux/drivers/block/piix.c Version 0.22 March 29, 1999 + * + * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer + * + * PIO mode setting function for Intel chipsets. + * For use instead of BIOS settings. + * + * 40-41 + * 42-43 + * + * 41 + * 43 + * + * | PIO 0 | c0 | 80 | 0 | + * | PIO 2 | SW2 | d0 | 90 | 4 | + * | PIO 3 | MW1 | e1 | a1 | 9 | + * | PIO 4 | MW2 | e3 | a3 | b | + * + * sitre = word40 & 0x4000; primary + * sitre = word42 & 0x4000; secondary + * + * 44 8421|8421 hdd|hdb + * + * 48 8421 hdd|hdc|hdb|hda udma enabled + * + * 0001 hda + * 0010 hdb + * 0100 hdc + * 1000 hdd + * + * 4a 84|21 hdb|hda + * 4b 84|21 hdd|hdc + * + * 00|00 udma 0 + * 01|01 udma 1 + * 10|10 udma 2 + * 11|11 reserved + * + * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#define PIIX_DMA_PROC 0 +#define PIIX_DEBUG_SET_XFER 0 +#define PIIX_DEBUG_DRIVE_INFO 0 + +/* + * Based on settings done by AMI BIOS + * (might be usefull if drive is not registered in CMOS for any reason). + */ +static void piix_tune_drive (ide_drive_t *drive, byte pio) +{ + unsigned long flags; + u16 master_data; + byte slave_data, speed; + int err; + int is_slave = (&HWIF(drive)->drives[1] == drive); + int master_port = HWIF(drive)->index ? 0x42 : 0x40; + int slave_port = 0x44; + /* ISP RTC */ + byte timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); + if (is_slave) { + master_data = master_data | 0x4000; + if (pio > 1) + /* enable PPE, IE and TIME */ + master_data = master_data | 0x0070; + pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); + slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); + slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1] + << (HWIF(drive)->index ? 4 : 0))); + } else { + master_data = master_data & 0xccf8; + if (pio > 1) + /* enable PPE, IE and TIME */ + master_data = master_data | 0x0007; + master_data = master_data | (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + save_flags(flags); + cli(); + pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data); + restore_flags(flags); + + switch(pio) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: + speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + break; + } + + err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); +} + +extern char *ide_xfer_verbose (byte xfer_rate); + +static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + int sitre; + short reg4042, reg44, reg48, reg4a; + byte speed; + int u_speed; + byte maslave = hwif->channel ? 0x42 : 0x40; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + int a_speed = 2 << (drive_number * 4); + int u_flag = 1 << drive_number; + + pci_read_config_word(dev, maslave, ®4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + +#if PIIX_DEBUG_SET_XFER + printk("PIIX%s: DMA enable ", + (dev->device == PCI_DEVICE_ID_INTEL_82371FB_0) ? "a" : + (dev->device == PCI_DEVICE_ID_INTEL_82371FB_1) ? "b" : + (dev->device == PCI_DEVICE_ID_INTEL_82371SB_1) ? "3" : + (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? "4" : " UNKNOWN" ); +#endif /* PIIX_DEBUG_SET_XFER */ + + if (id->dma_ultra && (ultra)) { + if (!(reg48 & u_flag)) { + pci_write_config_word(dev, 0x48, reg48|u_flag); + } + } else { + pci_write_config_word(dev, 0x48, reg48 & ~u_flag); + } + + if ((id->dma_ultra & 0x0004) && (ultra)) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0404; + } + u_speed = 2 << (drive_number * 4); + if (!(reg4a & u_speed)) { + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0202; + } + u_speed = 1 << (drive_number * 4); + if (!(reg4a & u_speed)) { + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0101; + } + u_speed = 0 << (drive_number * 4); + if (!(reg4a & u_speed)) { + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + drive->id->dma_ultra &= ~0x0F0F; + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + drive->id->dma_ultra &= ~0x0F0F; + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_1word & 0x0004) { + drive->id->dma_ultra &= ~0x0F0F; + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + } + speed = XFER_SW_DMA_2; + } else { + return ide_dma_off_quietly; + } + + (void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + +#if PIIX_DEBUG_DRIVE_INFO + printk("%s: %s drive%d ", + drive->name, + ide_xfer_verbose(speed), + drive_number); + printk("\n"); +#endif /* PIIX_DEBUG_DRIVE_INFO */ + + return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +{ + int ultra = (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0; + switch (func) { + case ide_dma_check: + return piix_config_drive_for_dma(drive, ultra); + default : + break; + } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); +} + +void ide_init_piix (ide_hwif_t *hwif) +{ + hwif->tuneproc = &piix_tune_drive; +#if PIIX_DMA_PROC + hwif->dmaproc = &piix_dmaproc; +#endif /* PIIX_DMA_PROC */ +} diff -ur --new-file old/linux/drivers/block/ps2esdi.c new/linux/drivers/block/ps2esdi.c --- old/linux/drivers/block/ps2esdi.c Thu Jan 14 19:31:41 1999 +++ new/linux/drivers/block/ps2esdi.c Sun May 16 08:43:04 1999 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -108,7 +109,9 @@ u_int dma_arb_level; /* DMA arbitration level */ -static struct wait_queue *ps2esdi_int = NULL, *ps2esdi_wait_open = NULL; +static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); +static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open); + int no_int_yet; static int access_count[MAX_HD] = {0,}; static char ps2esdi_valid[MAX_HD] = {0,}; @@ -1138,15 +1141,7 @@ return (0); } break; - case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!inode->i_rdev) - return -EINVAL; - if (arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; + case BLKGETSIZE: if (arg) { if ((err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)))) @@ -1156,20 +1151,19 @@ return (0); } break; - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!inode->i_rdev) - return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); - RO_IOCTLS(inode->i_rdev, arg); + + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); } return (-EINVAL); } diff -ur --new-file old/linux/drivers/block/qd6580.c new/linux/drivers/block/qd6580.c --- old/linux/drivers/block/qd6580.c Wed May 6 23:42:54 1998 +++ new/linux/drivers/block/qd6580.c Thu May 13 20:04:54 1999 @@ -19,8 +19,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff -ur --new-file old/linux/drivers/block/raid5.c new/linux/drivers/block/raid5.c --- old/linux/drivers/block/raid5.c Fri May 8 09:17:13 1998 +++ new/linux/drivers/block/raid5.c Wed May 12 08:37:51 1999 @@ -91,7 +91,7 @@ void __wait_on_stripe(struct stripe_head *sh) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); PRINTK(("wait_on_stripe %lu\n", sh->sector)); sh->count++; @@ -1395,7 +1395,7 @@ goto abort; memset(raid_conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); - init_waitqueue(&raid_conf->wait_for_stripe); + init_waitqueue_head(&raid_conf->wait_for_stripe); PRINTK(("raid5_run(%d) called.\n", minor)); for (i = 0; i < mddev->nb_dev; i++) { diff -ur --new-file old/linux/drivers/block/rd.c new/linux/drivers/block/rd.c --- old/linux/drivers/block/rd.c Thu Apr 29 20:53:41 1999 +++ new/linux/drivers/block/rd.c Sun May 16 08:43:04 1999 @@ -72,6 +72,7 @@ */ #define MAJOR_NR RAMDISK_MAJOR #include +#include /* * We use a block size of 512 bytes in comparision to BLOCK_SIZE @@ -198,11 +199,10 @@ if (!arg) return -EINVAL; return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg); - case BLKSSZGET: /* Block size of media */ - if (!arg) return -EINVAL; - return put_user(rd_blocksizes[minor], (int *)arg); - - RO_IOCTLS(inode->i_rdev, arg); + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; @@ -482,6 +482,7 @@ memset(&inode, 0, sizeof(inode)); memset(&in_dentry, 0, sizeof(in_dentry)); inode.i_rdev = device; + init_waitqueue_head(&inode.i_wait); infile.f_mode = 1; /* read only */ infile.f_dentry = &in_dentry; in_dentry.d_inode = &inode; @@ -490,6 +491,7 @@ memset(&out_inode, 0, sizeof(out_inode)); memset(&out_dentry, 0, sizeof(out_dentry)); out_inode.i_rdev = ram_device; + init_waitqueue_head(&out_inode.i_wait); outfile.f_mode = 3; /* read/write */ outfile.f_dentry = &out_dentry; out_dentry.d_inode = &out_inode; @@ -517,7 +519,7 @@ } if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) { - printk("RAMDISK: image too big! (%d/%d blocks)\n", + printk("RAMDISK: image too big! (%d/%ld blocks)\n", nblocks, rd_length[unit] >> RDBLK_SIZE_BITS); goto done; } diff -ur --new-file old/linux/drivers/block/rz1000.c new/linux/drivers/block/rz1000.c --- old/linux/drivers/block/rz1000.c Tue Jan 5 00:07:27 1999 +++ new/linux/drivers/block/rz1000.c Thu May 13 20:04:54 1999 @@ -26,9 +26,10 @@ #include #include #include -#include #include -#include "ide.h" +#include + +#include #ifdef CONFIG_BLK_DEV_IDEPCI diff -ur --new-file old/linux/drivers/block/sl82c105.c new/linux/drivers/block/sl82c105.c --- old/linux/drivers/block/sl82c105.c Thu Mar 11 06:48:46 1999 +++ new/linux/drivers/block/sl82c105.c Thu May 13 20:04:54 1999 @@ -8,11 +8,11 @@ #include #include #include +#include #include #include -#include "ide.h" #include "ide_modes.h" void ide_init_sl82c105(ide_hwif_t *hwif) diff -ur --new-file old/linux/drivers/block/swim3.c new/linux/drivers/block/swim3.c --- old/linux/drivers/block/swim3.c Thu Mar 11 06:48:46 1999 +++ new/linux/drivers/block/swim3.c Wed May 12 08:36:27 1999 @@ -193,7 +193,7 @@ struct timer_list timeout; int timeout_pending; int ejected; - struct wait_queue *wait; + wait_queue_head_t wait; int wanted; struct device_node* media_bay; /* NULL when not in bay */ char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)]; @@ -1132,6 +1132,7 @@ fs->secpertrack = 18; fs->total_secs = 2880; fs->media_bay = mediabay; + init_waitqueue_head(&fs->wait); fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space); memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd)); diff -ur --new-file old/linux/drivers/block/trm290.c new/linux/drivers/block/trm290.c --- old/linux/drivers/block/trm290.c Sat Aug 8 02:56:09 1998 +++ new/linux/drivers/block/trm290.c Thu May 13 20:04:54 1999 @@ -134,11 +134,10 @@ #include #include #include +#include #include -#include "ide.h" - static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { ide_hwif_t *hwif = HWIF(drive); @@ -185,7 +184,7 @@ break; /* always use PIO for writes */ #endif case ide_dma_read: - if (!(count = ide_build_dmatable(drive))) + if (!(count = ide_build_dmatable(drive, func))) break; /* try PIO instead of DMA */ trm290_prepare_drive(drive, 1); /* select DMA xfer */ outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base); diff -ur --new-file old/linux/drivers/block/umc8672.c new/linux/drivers/block/umc8672.c --- old/linux/drivers/block/umc8672.c Wed May 6 23:42:54 1998 +++ new/linux/drivers/block/umc8672.c Thu May 13 20:04:54 1999 @@ -47,8 +47,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff -ur --new-file old/linux/drivers/block/via82c586.c new/linux/drivers/block/via82c586.c --- old/linux/drivers/block/via82c586.c Fri Nov 13 19:29:44 1998 +++ new/linux/drivers/block/via82c586.c Thu May 13 20:04:54 1999 @@ -1,18 +1,44 @@ /* - * linux/drivers/block/via82c586.c Version 0.01 Aug 16, 1998 + * linux/drivers/block/via82c586.c Version 0.03 Nov. 19, 1998 * - * Copyright (C) 1998 Michel Aubry - * Copyright (C) 1998 Andre Hedrick + * Copyright (C) 1998 Michel Aubry, Maintainer + * Copyright (C) 1998 Andre Hedrick, Integrater * * The VIA MVP-3 is reported OK with UDMA. + * The TX Pro III is also reported OK with UDMA. * - * VIA chips also have a single FIFO, with the same 64 bytes deep buffer (16 levels - * of 4 bytes each). - * However, VIA chips can have the buffer split either 8:8 levels, 16:0 levels or - * 0:16 levels between both channels. One could think of using this feature, as even - * if no level of FIFO is given to a given channel, one can always reach ATAPI drives - * through it, or, if one channel is unused, configuration defaults to an even split - * FIFO levels. + * VIA chips also have a single FIFO, with the same 64 bytes deep + * buffer (16 levels of 4 bytes each). + * + * However, VIA chips can have the buffer split either 8:8 levels, + * 16:0 levels or 0:16 levels between both channels. One could think + * of using this feature, as even if no level of FIFO is given to a + * given channel, one can for instance always reach ATAPI drives through + * it, or, if one channel is unused, configuration defaults to + * an even split FIFO levels. + * + * This feature is available only through a kernel command line : + * "splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan". + * where: Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4. + * + * If Chan == 1: + * gives all the fifo to channel 0, + * sets its threshold to Thr0/4, + * and disables any dma access to channel 1. + * + * If chan == 2: + * gives all the fifo to channel 1, + * sets its threshold to Thr1/4, + * and disables any dma access to channel 0. + * + * If chan == 3 or 4: + * shares evenly fifo between channels, + * gives channel 0 a threshold of Thr0/4, + * and channel 1 a threshold of Thr1/4. + * + * Note that by default (if no command line is provided) and if a channel + * has been disabled in Bios, all the fifo is given to the active channel, + * and its threshold is set to 3/4. */ #include @@ -24,9 +50,255 @@ #include #include #include +#include #include +#include + #include -#include "ide.h" + +#define DISPLAY_VIA_TIMINGS + +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static char *FIFO_str[] = { + " 1 ", + "3/4", + "1/2", + "1/4" +}; + +static char *control3_str[] = { + "No limitation", + "64", + "128", + "192" +}; + +static int via_get_info(char *, char **, off_t, int, int); +extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static struct pci_dev *bmide_dev; + +static char * print_apollo_drive_config (char *buf, struct pci_dev *dev) +{ + int rc; + unsigned int time; + byte tm; + char *p = buf; + + /* Drive Timing Control */ + rc = pci_read_config_dword(dev, 0x48, &time); + p += sprintf(p, "Act Pls Width: %02d %02d %02d %02d\n", + ((time & 0xf0000000)>>28) + 1, + ((time & 0xf00000)>>20) + 1, + ((time & 0xf000)>>12) + 1, + ((time & 0xf0)>>4) + 1 ); + p += sprintf(p, "Recovery Time: %02d %02d %02d %02d\n", + ((time & 0x0f000000)>>24) + 1, + ((time & 0x0f0000)>>16) + 1, + ((time & 0x0f00)>>8) + 1, + (time & 0x0f) + 1 ); + + /* Address Setup Time */ + rc = pci_read_config_byte(dev, 0x4C, &tm); + p += sprintf(p, "Add. Setup T.: %01dT %01dT %01dT %01dT\n", + ((tm & 0xc0)>>6) + 1, + ((tm & 0x30)>>4) + 1, + ((tm & 0x0c)>>2) + 1, + (tm & 0x03) + 1 ); + + /* UltraDMA33 Extended Timing Control */ + rc = pci_read_config_dword(dev, 0x50, &time); + p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n"); + p += sprintf(p, "Enable Meth.: %01d %01d %01d %01d\n", + (time & 0x80000000) ? 1 : 0, + (time & 0x800000) ? 1 : 0, + (time & 0x8000) ? 1 : 0, + (time & 0x80) ? 1 : 0 ); + p += sprintf(p, "Enable: %s %s %s %s\n", + (time & 0x40000000) ? "yes" : "no ", + (time & 0x400000) ? "yes" : "no ", + (time & 0x4000) ? "yes" : "no ", + (time & 0x40) ? "yes" : "no " ); + p += sprintf(p, "Transfer Mode: %s %s %s %s\n", + (time & 0x20000000) ? "PIO" : "DMA", + (time & 0x200000) ? "PIO" : "DMA", + (time & 0x2000) ? "PIO" : "DMA", + (time & 0x20) ? "PIO" : "DMA" ); + p += sprintf(p, "Cycle Time: %01dT %01dT %01dT %01dT\n", + ((time & 0x03000000)>>24) + 2, + ((time & 0x030000)>>16) + 2, + ((time & 0x0300)>>8) + 2, + (time & 0x03) + 2 ); + + return (char *)p; +} + +static char * print_apollo_ide_config (char *buf, struct pci_dev *dev) +{ + byte time, tmp; + unsigned short size0, size1; + int rc; + char *p = buf; + + rc = pci_read_config_byte(dev, 0x41, &time); + p += sprintf(p, "Prefetch Buffer : %s %s\n", + (time & 128) ? "on " : "off", + (time & 32) ? "on " : "off" ); + p += sprintf(p, "Post Write Buffer: %s %s\n", + (time & 64) ? "on " : "off", + (time & 16) ? "on " : "off" ); + + /* FIFO configuration */ + rc = pci_read_config_byte(dev, 0x43, &time); + tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3); + p += sprintf(p, "FIFO Conf/Chan. : %02d %02d\n", + 16 - tmp, tmp); + tmp = (time & 0x0F)>>2; + p += sprintf(p, "Threshold Prim. : %s %s\n", + FIFO_str[tmp], + FIFO_str[time & 0x03] ); + + /* chipset Control3 */ + rc = pci_read_config_byte(dev, 0x46, &time); + p += sprintf(p, "Read DMA FIFO flush: %s %s\n", + (time & 0x80) ? "on " : "off", + (time & 0x40) ? "on " : "off" ); + p += sprintf(p, "End Sect. FIFO flush: %s %s\n", + (time & 0x20) ? "on " : "off", + (time & 0x10) ? "on " : "off" ); + p += sprintf(p, "Max DRDY Pulse Width: %s %s\n", + control3_str[(time & 0x03)], + (time & 0x03) ? "PCI clocks" : "" ); + + /* Primary and Secondary sector sizes */ + rc = pci_read_config_word(dev, 0x60, &size0); + rc = pci_read_config_word(dev, 0x68, &size1); + p += sprintf(p, "Bytes Per Sector: %03d %03d\n", + size0 & 0xfff, + size1 & 0xfff ); + + return (char *)p; +} + +static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev) +{ + byte t; + int rc; + char *p = buf; + unsigned short c; + byte l, l_max; + + rc = pci_read_config_word(dev, 0x04, &c); + rc = pci_read_config_byte(dev, 0x44, &t); + rc = pci_read_config_byte(dev, 0x0d, &l); + rc = pci_read_config_byte(dev, 0x3f, &l_max); + + p += sprintf(p, "Command register = 0x%x\n", c); + p += sprintf(p, "Master Read Cycle IRDY %d Wait State\n", + (t & 64) >>6 ); + p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n", + (t & 32) >> 5 ); + p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n", + (t & 16) ? "on " : "off" ); + p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n", + (t & 8) ? "on " : "off" ); + p += sprintf(p, "Latency timer = %d (max. = %d)\n", + l, l_max); + + return (char *)p; +} + +static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev) +{ + byte t; + int rc; + char *p = buf; + rc = pci_read_config_byte(dev, 0x45, &t); + p += sprintf(p, "Interrupt Steering Swap: %s\n", + (t & 64) ? "on ":"off" ); + + return (char *)p; +} + +static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev, + unsigned short n) +{ + /* + * at that point we can be sure that register 0x20 of the + * chipset contains the right address... + */ + unsigned int bibma; + int rc; + byte c0, c1; + char *p = buf; + + rc = pci_read_config_dword(dev, 0x20, &bibma); + bibma = (bibma & 0xfff0) ; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb((unsigned short)bibma + 0x02); + c1 = inb((unsigned short)bibma + 0x0a); + + if (n == 0) { + /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/ + p += sprintf(p, "both channels togth: %s %s\n", + (c0&0x80) ? "no" : "yes", + (c1&0x80) ? "no" : "yes" ); + } else { + /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/ + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", + (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", + (c1&0x40) ? "yes" : "no " ); + } + + return (char *)p; +} + +static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +{ + /* + * print what /proc/via displays, + * if required from DISPLAY_APOLLO_TIMINGS + */ + char *p = buffer; + /* Parameter of chipset : */ + + /* Miscellaneous control 1 */ + p = print_apollo_chipset_control1(buffer, bmide_dev); + + /* Miscellaneous control 2 */ + p = print_apollo_chipset_control2(p, bmide_dev); + /* Parameters of drives: */ + + /* Header */ + p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n"); + p = print_apollo_chipset_control3(p, bmide_dev, 0); + p = print_apollo_ide_config(p, bmide_dev); + p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n"); + p = print_apollo_chipset_control3(p, bmide_dev, 1); + p = print_apollo_drive_config(p, bmide_dev); + + return p-buffer; /* hoping it is less than 4K... */ +} + +#endif /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */ + +/* + * Used to set Fifo configuration via kernel command line: + */ + +byte fifoconfig = 0; +static byte newfifo = 0; + +/* Used to just intialize once Fifo configuration */ +static short int done = 0; /* * Set VIA Chipset Timings for (U)DMA modes enabled. @@ -37,49 +309,162 @@ static void set_via_timings (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; - byte post = hwif->channel ? 0xc0 : 0x30; - byte flush = hwif->channel ? 0xa0 : 0x50; + byte post = hwif->channel ? 0x30 : 0xc0; + byte flush = hwif->channel ? 0x50 : 0xa0; + int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) : + (((newfifo & 0x60) == 0x60) ? 1 : 0); byte via_config = 0; int rc = 0, errors = 0; printk("%s: VIA Bus-Master ", hwif->name); - if (!hwif->dma_base) { - printk(" ERROR, NO DMA_BASE\n"); - return; - } - - /* setting IDE read prefetch buffer and IDE post write buffer. + /* + * setting IDE read prefetch buffer and IDE post write buffer. * (This feature allows prefetched reads and post writes). */ - if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) { - errors++; - goto via_error; - } - if ((rc = pci_write_config_byte(dev, 0x41, via_config | post))) { + if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) errors++; - goto via_error; + + if (mask) { + if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post))) + errors++; + } else { + if ((rc = pci_write_config_byte(dev, 0x41, via_config | post))) + errors++; } - /* setting Channel read and End-of-sector FIFO flush. + /* + * setting Channel read and End-of-sector FIFO flush. * (This feature ensures that FIFO flush is enabled: * - for read DMA when interrupt asserts the given channel. * - at the end of each sector for the given channel.) */ - if ((rc = pci_read_config_byte(dev, 0x46, &via_config))) { + if ((rc = pci_read_config_byte(dev, 0x46, &via_config))) errors++; - goto via_error; + + if (mask) { + if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush))) + errors++; + } else { + if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush))) + errors++; } - if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush))) { - errors++; - goto via_error; + + if (!hwif->dma_base) + printk("Config %s. No DMA Enabled\n", + errors ? "ERROR":"Success"); + else + printk("(U)DMA Timing Config %s\n", + errors ? "ERROR" : "Success"); +} + +/* + * Sets VIA 82c586 FIFO configuration: + * This chipsets gets a splitable fifo. This can be driven either by command + * line option (eg "splitfifo=2,2,3" which asks this driver to switch all the + * 16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma + * triggering. + */ + +static int via_set_fifoconfig(ide_hwif_t *hwif) +{ + byte fifo; + unsigned int timings; + struct pci_dev *dev = hwif->pci_dev; + + /* read port configuration */ + if (pci_read_config_dword(dev, 0x40, &timings)) + return 1; + + /* first read actual fifo config: */ + if (pci_read_config_byte(dev, 0x43, &fifo)) + return 1; + + /* keep 4 and 7 bit as they seem to differ between chipsets flavors... */ + newfifo = fifo & 0x90; + + if (fifoconfig) { + /* we received a config request from kernel command line: */ + newfifo |= fifoconfig & 0x6f; + } else { + /* If ever just one channel is unused, allocate all fifo levels to it + * and give it a 3/4 threshold for (u)dma transfers. + * Otherwise, share it evenly between channels: + */ + if ((timings & 3) == 2) { + /* only primary channel is enabled + * 16 buf. to prim. chan. thresh=3/4 + */ + newfifo |= 0x06; + } else if ((timings & 3) == 1) { + /* only secondary channel is enabled! + * 16 buffers to sec. ch. thresh=3/4 + */ + newfifo |= 0x69; + } else { + /* fifo evenly distributed: */ + newfifo |= 0x2a; + } } -via_error: - printk("(U)DMA Timing Config %s\n", errors ? "ERROR" : "Success"); + /* write resulting configuration to chipset: */ + if (pci_write_config_byte(dev, 0x43, newfifo)) + return 1; + + /* and then reread it to get the actual one */ + if (pci_read_config_byte(dev, 0x43, &newfifo)) + return 1; + + /* print a kernel report: */ + printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n", + ((newfifo & 0x60) == 0x60) ? " 0" : + ((newfifo & 0x60) ? " 8" : "16"), + !(newfifo & 0x0c) ? "1" : + (!(newfifo & 0x08) ? "3/4" : + (newfifo & 0x04) ? "1/4" : "1/2")); + + printk(" %s Second. buffers, threshold = %s\n", + ((newfifo & 0x60) == 0x60) ? "16" : + ((newfifo & 0x60) ? " 8" : " 0"), + !(newfifo & 0x03) ? "1" : + (!(newfifo & 0x02) ? "3/4" : + (newfifo & 0x01) ? "1/4" : "1/2")); + +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) + bmide_dev = hwif->pci_dev; + via_display_info = &via_get_info; +#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ + return 0; +} + +/* + * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) + * checks if channel "channel" of if hwif is dma + * capable or not, according to kernel command line, + * and the new fifo settings. + * It calls "ide_setup_dma" on capable mainboards, and + * bypasses the setup if not capable. + */ + +void ide_dmacapable_via82c586 (ide_hwif_t *hwif, unsigned long dmabase) +{ + if (!done) { + via_set_fifoconfig(hwif); + done = 1; + } + + /* + * check if any fifo is available for requested port: + */ + if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) || + ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) { + printk(" %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name); + } else { + ide_setup_dma(hwif, dmabase, 8); + } } -void ide_init_via82c586 (ide_hwif_t *hwif) +__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif)) { set_via_timings(hwif); } diff -ur --new-file old/linux/drivers/block/xd.c new/linux/drivers/block/xd.c --- old/linux/drivers/block/xd.c Thu Jan 7 17:46:58 1999 +++ new/linux/drivers/block/xd.c Sun May 16 08:43:04 1999 @@ -49,6 +49,7 @@ #define MAJOR_NR XT_DISK_MAJOR #include +#include #include "xd.h" @@ -159,7 +160,8 @@ xd_release, /* release */ block_fsync /* fsync */ }; -static struct wait_queue *xd_wait_int = NULL, *xd_wait_open = NULL; +static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); +static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open); static u_char xd_valid[XD_MAXDRIVES] = { 0,0 }; static u_char xd_drives = 0, xd_irq = 5, xd_dma = 3, xd_maxsectors; static u_char xd_override __initdata = 0, xd_type = 0; @@ -167,7 +169,7 @@ static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0,0,0,0,0,0 }; static volatile int xdc_busy = 0; -static struct wait_queue *xdc_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(xdc_wait); typedef void (*timeout_fn)(unsigned long); static struct timer_list xd_timer = { NULL, NULL, 0, 0, (timeout_fn) xd_wakeup }, @@ -336,21 +338,9 @@ g.start = xd_struct[MINOR(inode->i_rdev)].start_sect; return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], (long*) arg); case BLKGETSIZE: if (!arg) return -EINVAL; return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg); - case BLKFLSBUF: /* Return devices size */ - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; @@ -368,7 +358,15 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return xd_reread_partitions(inode->i_rdev); - RO_IOCTLS(inode->i_rdev,arg); + + case BLKFLSBUF: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + default: return -EINVAL; } diff -ur --new-file old/linux/drivers/cdrom/aztcd.c new/linux/drivers/cdrom/aztcd.c --- old/linux/drivers/cdrom/aztcd.c Mon Aug 24 22:02:43 1998 +++ new/linux/drivers/cdrom/aztcd.c Wed May 12 22:27:37 1999 @@ -303,7 +303,7 @@ static char azt_auto_eject = AZT_AUTO_EJECT; static int AztTimeout, AztTries; -static struct wait_queue *azt_waitq = NULL; +static DECLARE_WAIT_QUEUE_HEAD(azt_waitq); static struct timer_list delay_timer = { NULL, NULL, 0, 0, NULL }; static struct azt_DiskInfo DiskInfo; diff -ur --new-file old/linux/drivers/cdrom/cdu31a.c new/linux/drivers/cdrom/cdu31a.c --- old/linux/drivers/cdrom/cdu31a.c Sun Dec 20 13:36:47 1998 +++ new/linux/drivers/cdrom/cdu31a.c Wed May 12 22:27:37 1999 @@ -278,7 +278,7 @@ static volatile int sony_inuse = 0; /* Is the drive in use? Only one operation at a time allowed */ -static struct wait_queue * sony_wait = NULL; /* Things waiting for the drive */ +static DECLARE_WAIT_QUEUE_HEAD(sony_wait); /* Things waiting for the drive */ static struct task_struct *has_cd_task = NULL; /* The task that is currently using the CDROM drive, or @@ -311,7 +311,7 @@ /* The interrupt handler will wake this queue up when it gets an interrupts. */ -static struct wait_queue *cdu31a_irq_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait); static int curr_control_reg = 0; /* Current value of the control register */ @@ -577,13 +577,13 @@ abort_read_started = 0; /* If something was waiting, wake it up now. */ - if (cdu31a_irq_wait != NULL) + if (waitqueue_active(&cdu31a_irq_wait)) { disable_interrupts(); wake_up(&cdu31a_irq_wait); } } - else if (cdu31a_irq_wait != NULL) + else if (waitqueue_active(&cdu31a_irq_wait)) { disable_interrupts(); wake_up(&cdu31a_irq_wait); diff -ur --new-file old/linux/drivers/cdrom/cm206.c new/linux/drivers/cdrom/cm206.c --- old/linux/drivers/cdrom/cm206.c Thu Mar 11 02:01:57 1999 +++ new/linux/drivers/cdrom/cm206.c Wed May 12 22:27:37 1999 @@ -262,8 +262,8 @@ int openfiles; ush sector[READ_AHEAD*RAW_SECTOR_SIZE/2]; /* buffered cd-sector */ int sector_first, sector_last; /* range of these sectors */ - struct wait_queue * uart; /* wait queues for interrupt */ - struct wait_queue * data; + wait_queue_head_t uart; /* wait queues for interrupt */ + wait_queue_head_t data; struct timer_list timer; /* time-out */ char timed_out; signed char max_sectors; /* number of sectors that fit in adapter mem */ @@ -360,7 +360,7 @@ debug(("receiving #%d: 0x%x\n", cd->ur_w, cd->ur[cd->ur_w])); cd->ur_w++; cd->ur_w %= UR_SIZE; if (cd->ur_w == cd->ur_r) debug(("cd->ur overflow!\n")); - if (cd->uart && cd->background < 2) { + if (waitqueue_active(&cd->uart) && cd->background < 2) { del_timer(&cd->timer); wake_up_interruptible(&cd->uart); } @@ -368,7 +368,7 @@ /* data ready in fifo? */ else if (cd->intr_ds & ds_data_ready) { if (cd->background) ++cd->adapter_last; - if (cd->data && (cd->wait_back || !cd->background)) { + if (waitqueue_active(&cd->data) && (cd->wait_back || !cd->background)) { del_timer(&cd->timer); wake_up_interruptible(&cd->data); } @@ -419,12 +419,12 @@ { cd->timed_out = 1; debug(("Timing out\n")); - wake_up_interruptible((struct wait_queue **) who); + wake_up_interruptible((wait_queue_head_t *)who); } /* This function returns 1 if a timeout occurred, 0 if an interrupt happened */ -int sleep_or_timeout(struct wait_queue ** wait, int timeout) +int sleep_or_timeout(wait_queue_head_t *wait, int timeout) { cd->timed_out=0; cd->timer.data=(unsigned long) wait; @@ -442,7 +442,7 @@ void cm206_delay(int nr_jiffies) { - struct wait_queue * wait = NULL; + DECLARE_WAIT_QUEUE_HEAD(wait); sleep_or_timeout(&wait, nr_jiffies); } diff -ur --new-file old/linux/drivers/cdrom/gscd.c new/linux/drivers/cdrom/gscd.c --- old/linux/drivers/cdrom/gscd.c Sat Oct 31 19:28:25 1998 +++ new/linux/drivers/cdrom/gscd.c Sun May 16 00:05:36 1999 @@ -76,7 +76,7 @@ MODULE_PARM(gscd, "h"); /* Kommt spaeter vielleicht noch mal dran ... - * static struct wait_queue *gscd_waitq = NULL; + * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); */ static void gscd_transfer (void); diff -ur --new-file old/linux/drivers/cdrom/mcd.c new/linux/drivers/cdrom/mcd.c --- old/linux/drivers/cdrom/mcd.c Tue Apr 13 01:18:28 1999 +++ new/linux/drivers/cdrom/mcd.c Wed May 12 22:27:37 1999 @@ -162,7 +162,7 @@ MODULE_PARM(mcd, "1-2i"); static int McdTimeout, McdTries; -static struct wait_queue *mcd_waitq = NULL; +static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq); static struct mcd_DiskInfo DiskInfo; static struct mcd_Toc Toc[MAX_TRACKS]; diff -ur --new-file old/linux/drivers/cdrom/mcdx.c new/linux/drivers/cdrom/mcdx.c --- old/linux/drivers/cdrom/mcdx.c Sun Dec 20 13:36:47 1998 +++ new/linux/drivers/cdrom/mcdx.c Wed May 12 22:27:37 1999 @@ -150,9 +150,9 @@ struct s_drive_stuff { /* waitqueues */ - struct wait_queue *busyq; - struct wait_queue *lockq; - struct wait_queue *sleepq; + wait_queue_head_t busyq; + wait_queue_head_t lockq; + wait_queue_head_t sleepq; /* flags */ volatile int introk; /* status of last irq operation */ @@ -1046,6 +1046,10 @@ stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; stuffp->wreg_hcon = stuffp->wreg_reset + 1; stuffp->wreg_chn = stuffp->wreg_hcon + 1; + + init_waitqueue_head(&stuffp->busyq); + init_waitqueue_head(&stuffp->lockq); + init_waitqueue_head(&stuffp->sleepq); /* check if i/o addresses are available */ if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { diff -ur --new-file old/linux/drivers/cdrom/optcd.c new/linux/drivers/cdrom/optcd.c --- old/linux/drivers/cdrom/optcd.c Sun Apr 25 02:49:37 1999 +++ new/linux/drivers/cdrom/optcd.c Wed May 12 22:27:37 1999 @@ -257,7 +257,7 @@ /* Timed waiting for status or data */ static int sleep_timeout; /* max # of ticks to sleep */ -static struct wait_queue *waitq = NULL; +static DECLARE_WAIT_QUEUE_HEAD(waitq); static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL}; #define SET_TIMER(func, jifs) \ diff -ur --new-file old/linux/drivers/cdrom/sbpcd.c new/linux/drivers/cdrom/sbpcd.c --- old/linux/drivers/cdrom/sbpcd.c Sun Dec 20 13:36:47 1998 +++ new/linux/drivers/cdrom/sbpcd.c Sun May 16 00:05:36 1999 @@ -585,7 +585,7 @@ /*==========================================================================*/ #if FUTURE -static struct wait_queue *sbp_waitq = NULL; +static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq); #endif FUTURE static int teac=SBP_TEAC_SPEED; @@ -612,7 +612,7 @@ static volatile u_char busy_data=0; static volatile u_char busy_audio=0; /* true semaphores would be safer */ #endif OLD_BUSY -static struct semaphore ioctl_read_sem = MUTEX; +static DECLARE_MUTEX(ioctl_read_sem); static u_long timeout; static volatile u_char timed_out_delay=0; static volatile u_char timed_out_data=0; diff -ur --new-file old/linux/drivers/cdrom/sjcd.c new/linux/drivers/cdrom/sjcd.c --- old/linux/drivers/cdrom/sjcd.c Tue Apr 13 01:18:32 1999 +++ new/linux/drivers/cdrom/sjcd.c Wed May 12 22:27:37 1999 @@ -115,7 +115,7 @@ MODULE_PARM(sjcd_base, "i"); #endif -static struct wait_queue *sjcd_waitq = NULL; +static DECLARE_WAIT_QUEUE_HEAD(sjcd_waitq); /* * Data transfer. diff -ur --new-file old/linux/drivers/cdrom/sonycd535.c new/linux/drivers/cdrom/sonycd535.c --- old/linux/drivers/cdrom/sonycd535.c Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/cdrom/sonycd535.c Wed May 12 22:27:37 1999 @@ -261,7 +261,7 @@ static int sony535_irq_used = CDU535_INTERRUPT; /* The interrupt handler will wake this queue up when it gets an interrupt. */ -static struct wait_queue *cdu535_irq_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); /* @@ -318,7 +318,7 @@ cdu535_interrupt(int irq, void *dev_id, struct pt_regs *regs) { disable_interrupts(); - if (cdu535_irq_wait != NULL) + if (wait_queue_active(&cdu535_irq_wait)) wake_up(&cdu535_irq_wait); else printk(CDU535_MESSAGE_NAME diff -ur --new-file old/linux/drivers/char/atixlmouse.c new/linux/drivers/char/atixlmouse.c --- old/linux/drivers/char/atixlmouse.c Mon Aug 24 22:02:43 1998 +++ new/linux/drivers/char/atixlmouse.c Wed May 12 22:27:37 1999 @@ -67,7 +67,7 @@ int present; int ready; int active; - struct wait_queue *wait; + wait_queue_head_t wait; struct fasync_struct *fasync; } mouse; @@ -223,7 +223,7 @@ mouse.ready = 0; mouse.buttons = mouse.latch_buttons = 0; mouse.dx = mouse.dy = 0; - mouse.wait = NULL; + init_waitqueue_head(&mouse.wait); printk("Bus mouse detected and installed.\n"); misc_register(&atixl_mouse); return 0; diff -ur --new-file old/linux/drivers/char/bttv.c new/linux/drivers/char/bttv.c --- old/linux/drivers/char/bttv.c Sun Apr 25 02:49:37 1999 +++ new/linux/drivers/char/bttv.c Wed May 12 17:41:12 1999 @@ -3421,10 +3421,10 @@ btv->risc_jmp=NULL; btv->vbi_odd=NULL; btv->vbi_even=NULL; - btv->vbiq=NULL; - btv->capq=NULL; - btv->capqo=NULL; - btv->capqe=NULL; + init_waitqueue_head(&btv->vbiq); + init_waitqueue_head(&btv->capq); + init_waitqueue_head(&btv->capqo); + init_waitqueue_head(&btv->capqe); btv->vbip=VBIBUF_SIZE; btv->id=dev->device; diff -ur --new-file old/linux/drivers/char/bttv.h new/linux/drivers/char/bttv.h --- old/linux/drivers/char/bttv.h Sun Apr 25 02:49:37 1999 +++ new/linux/drivers/char/bttv.h Wed May 12 17:41:12 1999 @@ -122,10 +122,10 @@ u32 *vbi_even; u32 bus_vbi_even; u32 bus_vbi_odd; - struct wait_queue *vbiq; - struct wait_queue *capq; - struct wait_queue *capqo; - struct wait_queue *capqe; + wait_queue_head_t vbiq; + wait_queue_head_t capq; + wait_queue_head_t capqo; + wait_queue_head_t capqe; int vbip; u32 *risc_odd; diff -ur --new-file old/linux/drivers/char/busmouse.c new/linux/drivers/char/busmouse.c --- old/linux/drivers/char/busmouse.c Wed Dec 16 22:38:18 1998 +++ new/linux/drivers/char/busmouse.c Wed May 12 22:27:37 1999 @@ -277,7 +277,7 @@ mouse.buttons = 0x87; mouse.dx = 0; mouse.dy = 0; - mouse.wait = NULL; + init_waitqueue_head(&mouse.wait); printk(KERN_INFO "Logitech bus mouse detected, using IRQ %d.\n", mouse_irq); misc_register(&bus_mouse); diff -ur --new-file old/linux/drivers/char/console.c new/linux/drivers/char/console.c --- old/linux/drivers/char/console.c Thu Mar 11 01:51:35 1999 +++ new/linux/drivers/char/console.c Tue May 11 23:37:40 1999 @@ -2269,7 +2269,7 @@ def_color = 0x07; /* white */ ulcolor = 0x0f; /* bold white */ halfcolor = 0x08; /* grey */ - vt_cons[currcons]->paste_wait = 0; + init_waitqueue_head(&vt_cons[currcons]->paste_wait); reset_terminal(currcons, do_clear); } diff -ur --new-file old/linux/drivers/char/cyclades.c new/linux/drivers/char/cyclades.c --- old/linux/drivers/char/cyclades.c Mon Apr 12 19:09:47 1999 +++ new/linux/drivers/char/cyclades.c Sun May 16 08:43:04 1999 @@ -697,7 +697,7 @@ * allocated when the first cy_open occurs. */ static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; +DECLARE_MUTEX(tmp_buf_sem); /* * This is used to look up the divisor speeds and the timeouts @@ -1264,7 +1264,7 @@ TTY_OVERRUN; *tty->flip.char_buf_ptr++ = 0; /* If the flip buffer itself is - overflowing, we still loose + overflowing, we still lose the next incoming character. */ if(tty->flip.count @@ -2246,7 +2246,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, struct cyclades_port *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct cyclades_card *cinfo; unsigned long flags; int chip, channel,index; @@ -5210,9 +5210,9 @@ cy_callout_driver.init_termios; info->normal_termios = cy_serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; - info->shutdown_wait = 0; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->shutdown_wait); /* info->session */ /* info->pgrp */ info->read_status_mask = 0; @@ -5279,9 +5279,9 @@ cy_callout_driver.init_termios; info->normal_termios = cy_serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; - info->shutdown_wait = 0; + init_waitqueue(&info->open_wait); + init_waitqueue(&info->close_wait); + init_waitqueue(&info->shutdown_wait); /* info->session */ /* info->pgrp */ info->read_status_mask = diff -ur --new-file old/linux/drivers/char/dn_keyb.c new/linux/drivers/char/dn_keyb.c --- old/linux/drivers/char/dn_keyb.c Mon Apr 26 22:28:07 1999 +++ new/linux/drivers/char/dn_keyb.c Sun May 16 00:05:36 1999 @@ -47,7 +47,7 @@ static unsigned int kbd_mode=APOLLO_KBD_MODE_KEYB; static short mouse_dx,mouse_dy,mouse_buttons; static int mouse_ready=0,mouse_update_allowed=0,mouse_active=0; -static struct wait_queue *mouse_wait=NULL; +static DECLARE_WAIT_QUEUE_HEAD(mouse_wait); static struct fasync_struct *mouse_fasyncptr=NULL; #if 0 diff -ur --new-file old/linux/drivers/char/dtlk.c new/linux/drivers/char/dtlk.c --- old/linux/drivers/char/dtlk.c Fri Apr 16 17:20:23 1999 +++ new/linux/drivers/char/dtlk.c Wed May 12 22:27:37 1999 @@ -87,7 +87,7 @@ static int dtlk_has_indexing; static unsigned int dtlk_portlist[] = {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0}; -static struct wait_queue *dtlk_process_list = NULL; +static wait_queue_head_t dtlk_process_list; static struct timer_list dtlk_timer; /* prototypes for file_operations struct */ @@ -382,7 +382,7 @@ init_timer(&dtlk_timer); dtlk_timer.function = dtlk_timer_tick; - dtlk_process_list = NULL; + init_waitqueue_head(&dtlk_process_list); return 0; } diff -ur --new-file old/linux/drivers/char/epca.c new/linux/drivers/char/epca.c --- old/linux/drivers/char/epca.c Tue Mar 16 23:21:51 1999 +++ new/linux/drivers/char/epca.c Wed May 12 22:27:37 1999 @@ -1268,7 +1268,7 @@ struct file *filp, struct channel *ch) { /* Begin block_til_ready */ - struct wait_queue wait = {current, NULL}; + DECLARE_WAITQUEUE(wait,current); int retval, do_clocal = 0; unsigned long flags; @@ -2236,8 +2236,8 @@ ch->blocked_open = 0; ch->callout_termios = pc_callout.init_termios; ch->normal_termios = pc_driver.init_termios; - ch->open_wait = 0; - ch->close_wait = 0; + init_waitqueue_head(&ch->open_wait); + init_waitqueue_head(&ch->close_wait); ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); if (!(ch->tmp_buf)) { diff -ur --new-file old/linux/drivers/char/esp.c new/linux/drivers/char/esp.c --- old/linux/drivers/char/esp.c Sat Oct 31 20:06:21 1998 +++ new/linux/drivers/char/esp.c Wed May 12 22:27:37 1999 @@ -169,7 +169,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf = 0; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int serial_paranoia_check(struct esp_struct *info, kdev_t device, const char *routine) @@ -2224,7 +2224,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct esp_struct *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -2676,6 +2676,10 @@ info->config.flow_off = flow_off; info->config.pio_threshold = pio_threshold; info->next_port = ports; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + init_waitqueue_head(&info->break_wait); ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", info->line, info->port, info->irq); diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/fdc-io.c new/linux/drivers/char/ftape/lowlevel/fdc-io.c --- old/linux/drivers/char/ftape/lowlevel/fdc-io.c Tue Dec 29 20:27:38 1998 +++ new/linux/drivers/char/ftape/lowlevel/fdc-io.c Wed May 12 22:27:37 1999 @@ -54,7 +54,7 @@ volatile int ftape_current_cylinder = -1; volatile fdc_mode_enum fdc_mode = fdc_idle; fdc_config_info fdc = {0}; -struct wait_queue *ftape_wait_intr = NULL; +DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); unsigned int ft_fdc_base = CONFIG_FT_FDC_BASE; unsigned int ft_fdc_irq = CONFIG_FT_FDC_IRQ; @@ -385,7 +385,7 @@ */ int fdc_interrupt_wait(unsigned int time) { - struct wait_queue wait = {current, NULL}; + DECLARE_WAITQUEUE(wait,current); sigset_t old_sigmask; static int resetting = 0; long timeout; diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/fdc-io.h new/linux/drivers/char/ftape/lowlevel/fdc-io.h --- old/linux/drivers/char/ftape/lowlevel/fdc-io.h Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/fdc-io.h Wed May 12 22:27:37 1999 @@ -209,7 +209,7 @@ */ extern volatile fdc_mode_enum fdc_mode; extern int fdc_setup_error; /* outdated ??? */ -extern struct wait_queue *ftape_wait_intr; +extern wait_queue_head_t ftape_wait_intr; extern int ftape_motor; /* fdc motor line state */ extern volatile int ftape_current_cylinder; /* track nr FDC thinks we're on */ extern volatile __u8 fdc_head; /* FDC head */ diff -ur --new-file old/linux/drivers/char/h8.c new/linux/drivers/char/h8.c --- old/linux/drivers/char/h8.c Mon Aug 24 22:02:44 1998 +++ new/linux/drivers/char/h8.c Sun May 16 00:05:36 1999 @@ -160,7 +160,7 @@ */ int cpu_speed_divisor = -1; int h8_event_mask = 0; -struct wait_queue *h8_monitor_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait); unsigned int h8_command_mask = 0; int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD; int h8_uthermal_window = UTH_HYSTERESIS; @@ -170,7 +170,7 @@ u_char h8_current_temp = 0; u_char h8_system_temp = 0; int h8_sync_channel = 0; -struct wait_queue *h8_sync_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait); int h8_init_performed; /* CPU speeds and clock divisor values */ diff -ur --new-file old/linux/drivers/char/hfmodem/main.c new/linux/drivers/char/hfmodem/main.c --- old/linux/drivers/char/hfmodem/main.c Mon Jan 18 03:28:06 1999 +++ new/linux/drivers/char/hfmodem/main.c Wed May 12 22:27:37 1999 @@ -638,6 +638,7 @@ hfmodem_state[0].ptt_out.seriobase = serio; hfmodem_state[0].ptt_out.pariobase = pario; hfmodem_state[0].ptt_out.midiiobase = midiio; + init_waitqueue_head(&hfmodem_state[0].wait); hfmodem_refclock_probe(); output_check(&hfmodem_state[0]); #if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC) @@ -703,7 +704,8 @@ int i; printk(hfmodem_drvinfo); - hfmodem_refclock_probe(); + init_waitqueue_head(&hfmode_state[0].wait); + hfmodem_refclock_probe(); output_check(&hfmodem_state[0]); #if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC) if (hw) diff -ur --new-file old/linux/drivers/char/isicom.c new/linux/drivers/char/isicom.c --- old/linux/drivers/char/isicom.c Fri May 7 20:05:30 1999 +++ new/linux/drivers/char/isicom.c Wed May 12 22:27:37 1999 @@ -80,7 +80,7 @@ static void isicom_start(struct tty_struct * tty); static unsigned char * tmp_buf = 0; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); /* baud index mappings from linux defns to isi */ @@ -870,7 +870,7 @@ static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port) { int do_clocal = 0, retval; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); /* block if port is in the process of being closed */ @@ -1858,7 +1858,8 @@ port->bh_tqueue.routine = isicom_bottomhalf; port->bh_tqueue.data = port; port->status = 0; - + init_waitqueue_head(&port->open_wait); + init_waitqueue_head(&port->close_wait); /* . . . */ } } diff -ur --new-file old/linux/drivers/char/joystick/joystick.c new/linux/drivers/char/joystick/joystick.c --- old/linux/drivers/char/joystick/joystick.c Wed Dec 2 04:05:05 1998 +++ new/linux/drivers/char/joystick/joystick.c Wed May 12 22:27:37 1999 @@ -491,7 +491,7 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count) #endif { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct js_event *buff = (void *) buf; struct js_list *curl; struct js_dev *jd; @@ -1081,7 +1081,7 @@ curd->next = NULL; curd->list = NULL; curd->port = port; - curd->wait = NULL; + init_waitqueue_head(&curd->wait); curd->open = open; curd->close = close; diff -ur --new-file old/linux/drivers/char/keyboard.c new/linux/drivers/char/keyboard.c --- old/linux/drivers/char/keyboard.c Mon Apr 26 22:21:42 1999 +++ new/linux/drivers/char/keyboard.c Sun May 16 19:12:38 1999 @@ -64,7 +64,7 @@ extern void ctrl_alt_del(void); -struct wait_queue * keypress_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(keypress_wait); struct console; int keyboard_wait_for_keypress(struct console *co) @@ -279,7 +279,8 @@ u_char type; /* the XOR below used to be an OR */ - int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; + int shift_final = (shift_state | kbd->slockstate) ^ + kbd->lockstate; ushort *key_map = key_maps[shift_final]; if (key_map != NULL) { @@ -311,6 +312,7 @@ /* we have at least to update shift_state */ #if 1 /* how? two almost equivalent choices follow */ compute_shiftstate(); + kbd->slockstate = 0; /* play it safe */ #else keysym = U(plain_map[keycode]); type = KTYP(keysym); @@ -472,6 +474,7 @@ static void boot_it(void) { + if (kbd->slockstate & ~shift_state) return; ctrl_alt_del(); } @@ -741,7 +744,7 @@ for(j=0; jlockstate ^ kbd->slockstate]) { + kbd->slockstate = 0; + chg_vc_kbd_slock(kbd, value); + } } /* diff -ur --new-file old/linux/drivers/char/lp.c new/linux/drivers/char/lp.c --- old/linux/drivers/char/lp.c Mon May 10 19:26:31 1999 +++ new/linux/drivers/char/lp.c Wed May 12 17:41:12 1999 @@ -187,15 +187,7 @@ /* if you have more than 3 printers, remember to increase LP_NO */ #define LP_NO 3 -struct lp_struct lp_table[LP_NO] = -{ - [0 ... LP_NO-1] = {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, - NULL, -#ifdef LP_STATS - 0, 0, {0}, -#endif - NULL, 0, 0, 0} -}; +struct lp_struct lp_table[LP_NO]; /* Test if printer is ready */ #define LP_READY(status) ((status) & LP_PBUSY) @@ -737,6 +729,7 @@ LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } + init_waitqueue_head(&(lp_table[minor].wait_q)); return 0; } @@ -928,6 +921,24 @@ unsigned int count = 0; unsigned int i; struct parport *port; + + for(i = 0; i < LP_NO; i++) { + lp_table[i].dev = NULL; + lp_table[i].flags = 0; + lp_table[i].chars = LP_INIT_CHAR; + lp_table[i].time = LP_INIT_TIME; + lp_table[i].wait = LP_INIT_WAIT; + lp_table[i].lp_buffer = NULL; +#ifdef LP_STATS + lp_table[i].lastcall = 0; + lp_table[i].runchars = 0; + memset(&lp_table[i].stats, 0, sizeof(struct lp_stats)); +#endif + init_waitqueue_head(&lp_table[i].wait_q); + lp_table[i].last_error = 0; + lp_table[i].irq_detected = 0; + lp_table[i].irq_missed = 0; + } switch (parport_nr[0]) { diff -ur --new-file old/linux/drivers/char/mem.c new/linux/drivers/char/mem.c --- old/linux/drivers/char/mem.c Mon May 10 19:18:34 1999 +++ new/linux/drivers/char/mem.c Sat May 15 03:15:02 1999 @@ -51,14 +51,8 @@ #if defined(CONFIG_PPC) || defined(CONFIG_MAC) extern void adbdev_init(void); #endif -#ifdef CONFIG_USB_UHCI -int uhci_init(void); -#endif -#ifdef CONFIG_USB_OHCI -int ohci_init(void); -#endif -#ifdef CONFIG_USB_OHCI_HCD -int ohci_hcd_init(void); +#ifdef CONFIG_USB +extern void usb_init(void); #endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, @@ -609,15 +603,7 @@ printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); #ifdef CONFIG_USB -#ifdef CONFIG_USB_UHCI - uhci_init(); -#endif -#ifdef CONFIG_USB_OHCI - ohci_init(); -#endif -#ifdef CONFIG_USB_OHCI_HCD - ohci_hcd_init(); -#endif + usb_init(); #endif #if defined (CONFIG_FB) fbmem_init(); diff -ur --new-file old/linux/drivers/char/msbusmouse.c new/linux/drivers/char/msbusmouse.c --- old/linux/drivers/char/msbusmouse.c Wed Dec 16 22:39:11 1998 +++ new/linux/drivers/char/msbusmouse.c Wed May 12 22:27:37 1999 @@ -195,7 +195,7 @@ mouse.present = mouse.active = mouse.ready = 0; mouse.buttons = 0x80; mouse.dx = mouse.dy = 0; - mouse.wait = NULL; + init_waitqueue_head(&mouse.wait); if (check_region(MS_MSE_CONTROL_PORT, 0x04)) return -ENODEV; diff -ur --new-file old/linux/drivers/char/msp3400.c new/linux/drivers/char/msp3400.c --- old/linux/drivers/char/msp3400.c Wed Feb 17 18:37:51 1999 +++ new/linux/drivers/char/msp3400.c Wed May 12 17:41:07 1999 @@ -83,7 +83,7 @@ /* thread */ struct task_struct *thread; - struct wait_queue *wq; + wait_queue_head_t wq; struct semaphore *notify; int active,restart,rmmod; @@ -523,7 +523,6 @@ current->fs->umask = 0; strcpy(current->comm,"msp3400"); - msp->wq = NULL; msp->thread = current; #ifdef __SMP__ @@ -748,7 +747,7 @@ { unsigned long flags; struct msp3400c *msp = data; - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); int i, val; /* lock_kernel(); */ @@ -844,7 +843,7 @@ static struct msp3400c *mspmix = NULL; /* ugly hack, should do something more sensible */ static int mixer_num; static int mixer_modcnt = 0; -static struct semaphore mixer_sem = MUTEX; +static DECLARE_MUTEX(mixer_sem); static int mix_to_v4l(int i) { @@ -1016,7 +1015,7 @@ static int msp3400c_attach(struct i2c_device *device) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp; int rev1,rev2; LOCK_FLAGS; @@ -1030,6 +1029,7 @@ msp->right = 65535; msp->bass = 32768; msp->treble = 32768; + init_waitqueue_head(&msp->wq); LOCK_I2C_BUS(msp->bus); if (-1 == msp3400c_reset(msp->bus)) { @@ -1069,7 +1069,6 @@ /* startup control thread */ MOD_INC_USE_COUNT; - msp->wq = NULL; msp->notify = &sem; kernel_thread(msp3400c_thread, (void *)msp, 0); down(&sem); @@ -1090,7 +1089,7 @@ static int msp3400c_detach(struct i2c_device *device) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp = (struct msp3400c*)device->data; LOCK_FLAGS; diff -ur --new-file old/linux/drivers/char/n_hdlc.c new/linux/drivers/char/n_hdlc.c --- old/linux/drivers/char/n_hdlc.c Fri Mar 12 17:20:38 1999 +++ new/linux/drivers/char/n_hdlc.c Wed May 12 22:27:37 1999 @@ -221,8 +221,8 @@ struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ /* Queues for select() functionality */ - struct wait_queue *read_wait; - struct wait_queue *write_wait; + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; int tbusy; /* reentrancy flag for tx wakeup code */ int woke_up; @@ -724,7 +724,7 @@ { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; - struct wait_queue wait = {current, NULL}; + DECLARE_WAITQUEUE(wait, current); N_HDLC_BUF *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) @@ -1006,8 +1006,8 @@ n_hdlc->magic = HDLC_MAGIC; n_hdlc->flags = 0; - n_hdlc->read_wait = NULL; - n_hdlc->write_wait = NULL; + init_waitqueue_head(&n_hdlc->read_wait); + init_waitqueue_head(&n_hdlc->write_wait); return n_hdlc; diff -ur --new-file old/linux/drivers/char/n_tty.c new/linux/drivers/char/n_tty.c --- old/linux/drivers/char/n_tty.c Sun Apr 25 02:49:37 1999 +++ new/linux/drivers/char/n_tty.c Tue May 11 23:37:40 1999 @@ -605,7 +605,7 @@ tty->canon_data++; if (tty->fasync) kill_fasync(tty->fasync, SIGIO); - if (tty->read_wait) + if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); return; } @@ -707,7 +707,7 @@ if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { if (tty->fasync) kill_fasync(tty->fasync, SIGIO); - if (tty->read_wait) + if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); } @@ -868,7 +868,7 @@ unsigned char *buf, size_t nr) { unsigned char *b = buf; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int c; int minimum, time; ssize_t retval = 0; @@ -1058,7 +1058,7 @@ const unsigned char * buf, size_t nr) { const unsigned char *b = buf; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int c; ssize_t retval = 0; diff -ur --new-file old/linux/drivers/char/pc110pad.c new/linux/drivers/char/pc110pad.c --- old/linux/drivers/char/pc110pad.c Sun Sep 6 02:01:45 1998 +++ new/linux/drivers/char/pc110pad.c Wed May 12 22:27:37 1999 @@ -48,7 +48,7 @@ /* driver/filesystem interface management */ -static struct wait_queue *queue; +static wait_queue_head_t queue; static struct fasync_struct *asyncptr; static int active=0; /* number of concurrent open()s */ @@ -656,6 +656,7 @@ return -EBUSY; } request_region(current_params.io, 4, "pc110pad"); + init_waitqueue_head(&queue); printk("PC110 digitizer pad at 0x%X, irq %d.\n", current_params.io,current_params.irq); misc_register(&pc110_pad); diff -ur --new-file old/linux/drivers/char/pc_keyb.c new/linux/drivers/char/pc_keyb.c --- old/linux/drivers/char/pc_keyb.c Mon Apr 26 22:43:01 1999 +++ new/linux/drivers/char/pc_keyb.c Tue May 11 23:37:40 1999 @@ -864,7 +864,7 @@ static ssize_t read_aux(struct file * file, char * buffer, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); ssize_t i = count; unsigned char c; @@ -964,7 +964,7 @@ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; - queue->proc_list = NULL; + init_waitqueue_head(&queue->proc_list); #ifdef INITIALIZE_MOUSE kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ diff -ur --new-file old/linux/drivers/char/pc_keyb.h new/linux/drivers/char/pc_keyb.h --- old/linux/drivers/char/pc_keyb.h Sat Feb 6 21:46:20 1999 +++ new/linux/drivers/char/pc_keyb.h Tue May 11 23:37:40 1999 @@ -124,7 +124,7 @@ struct aux_queue { unsigned long head; unsigned long tail; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; struct fasync_struct *fasync; unsigned char buf[AUX_BUF_SIZE]; }; diff -ur --new-file old/linux/drivers/char/pcxx.c new/linux/drivers/char/pcxx.c --- old/linux/drivers/char/pcxx.c Thu Mar 11 01:51:35 1999 +++ new/linux/drivers/char/pcxx.c Sun May 16 00:05:36 1999 @@ -326,7 +326,7 @@ static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval = 0; int do_clocal = 0; diff -ur --new-file old/linux/drivers/char/pcxx.h new/linux/drivers/char/pcxx.h --- old/linux/drivers/char/pcxx.h Sun Apr 13 19:18:20 1997 +++ new/linux/drivers/char/pcxx.h Sun May 16 00:05:36 1999 @@ -88,8 +88,8 @@ int blocked_open; int close_delay; int event; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; struct tq_struct tqueue; /* ------------ Async control data ------------- */ unchar modemfake; /* Modem values to be forced */ diff -ur --new-file old/linux/drivers/char/planb.c new/linux/drivers/char/planb.c --- old/linux/drivers/char/planb.c Mon May 10 19:17:28 1999 +++ new/linux/drivers/char/planb.c Sun May 16 00:05:36 1999 @@ -379,7 +379,7 @@ static void __planb_wait(struct planb *pb) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); add_wait_queue(&pb->lockq, &wait); repeat: diff -ur --new-file old/linux/drivers/char/planb.h new/linux/drivers/char/planb.h --- old/linux/drivers/char/planb.h Fri May 7 20:05:30 1999 +++ new/linux/drivers/char/planb.h Sun May 16 00:05:36 1999 @@ -175,7 +175,7 @@ unsigned int tab_size; int maxlines; int lock; - struct wait_queue *lockq; + wait_queue_head_t lockq; unsigned int irq; /* interrupt number */ volatile unsigned int intr_mask; @@ -190,13 +190,13 @@ unsigned long ch1_cmd_phys; volatile unsigned char *mask; /* Clipmask buffer */ int suspend; - struct wait_queue *suspendq; + wait_queue_head_t suspendq; struct planb_suspend suspended; int cmd_buff_inited; /* cmd buffer inited? */ int grabbing; unsigned int gcount; - struct wait_queue *capq; + wait_queue_head_t capq; int last_fr; int prev_last_fr; unsigned char *fbuffer; diff -ur --new-file old/linux/drivers/char/pty.c new/linux/drivers/char/pty.c --- old/linux/drivers/char/pty.c Sun Feb 7 02:28:37 1999 +++ new/linux/drivers/char/pty.c Wed May 12 17:41:15 1999 @@ -30,7 +30,7 @@ struct pty_struct { int magic; - struct wait_queue * open_wait; + wait_queue_head_t open_wait; }; #define PTY_MAGIC 0x5001 @@ -336,13 +336,13 @@ __initfunc(int pty_init(void)) { -#ifdef CONFIG_UNIX98_PTYS int i; -#endif /* Traditional BSD devices */ memset(&pty_state, 0, sizeof(pty_state)); + for (i = 0; i < NR_PTYS; i++) + init_waitqueue_head(&pty_state[i].open_wait); memset(&pty_driver, 0, sizeof(struct tty_driver)); pty_driver.magic = TTY_DRIVER_MAGIC; pty_driver.driver_name = "pty_master"; @@ -405,6 +405,8 @@ #ifdef CONFIG_UNIX98_PTYS printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS); for ( i = 0 ; i < UNIX98_NR_MAJORS ; i++ ) { + int j; + ptm_driver[i] = pty_driver; ptm_driver[i].name = "ptm"; ptm_driver[i].proc_entry = 0; @@ -417,6 +419,9 @@ ptm_driver[i].termios = ptm_termios[i]; ptm_driver[i].termios_locked = ptm_termios_locked[i]; ptm_driver[i].driver_state = ptm_state[i]; + + for (j = 0; j < NR_PTYS; j++) + init_waitqueue_head(&ptm_state[i][j].open_wait); pts_driver[i] = pty_slave_driver; pts_driver[i].name = "pts"; diff -ur --new-file old/linux/drivers/char/qpmouse.c new/linux/drivers/char/qpmouse.c --- old/linux/drivers/char/qpmouse.c Sat Oct 31 19:43:36 1998 +++ new/linux/drivers/char/qpmouse.c Tue May 11 23:37:40 1999 @@ -55,7 +55,7 @@ struct qp_queue { unsigned long head; unsigned long tail; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; struct fasync_struct *fasync; unsigned char buf[QP_BUF_SIZE]; }; @@ -258,7 +258,7 @@ static ssize_t read_qp(struct file * file, char * buffer, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); ssize_t i = count; unsigned char c; @@ -354,7 +354,7 @@ queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; - queue->proc_list = NULL; + init_waitqueue_head(&queue->proc_list); return 0; } diff -ur --new-file old/linux/drivers/char/radio-cadet.c new/linux/drivers/char/radio-cadet.c --- old/linux/drivers/char/radio-cadet.c Mon May 10 22:00:10 1999 +++ new/linux/drivers/char/radio-cadet.c Wed May 12 22:27:37 1999 @@ -34,7 +34,7 @@ static int curtuner=0; static int tunestat=0; static int sigstrength=0; -struct wait_queue *tunerq,*rdsq,*readq; +static wait_queue_head_t tunerq,rdsq,readq; struct timer_list tunertimer,rdstimer,readtimer; static __u8 rdsin=0,rdsout=0,rdsstat=0; static unsigned char rdsbuf[RDS_BUFFER]; @@ -75,7 +75,7 @@ rdstimer.function=cadet_wake; rdstimer.data=(unsigned long)1; rdstimer.expires=jiffies+(HZ/10); - rdsq=NULL; + init_waitqueue_head(&rdsq); add_timer(&rdstimer); sleep_on(&rdsq); @@ -260,7 +260,7 @@ tunertimer.function=cadet_wake; tunertimer.data=(unsigned long)0; tunertimer.expires=jiffies+(HZ/10); - tunerq=NULL; + init_waitqueue_head(&tunerq); add_timer(&tunertimer); sleep_on(&tunerq); cadet_gettune(); @@ -327,7 +327,7 @@ /* * Service pending read */ - if((rdsin!=rdsout)&&(readq!=NULL)) { + if( rdsin!=rdsout) { wake_up_interruptible(&readq); } @@ -369,7 +369,6 @@ return -EWOULDBLOCK; } interruptible_sleep_on(&readq); - readq=NULL; } while((iclose_delay = 50; info->callout_termios =callout_driver.init_termios; info->normal_termios = rocket_driver.init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; @@ -807,7 +809,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct r_port *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; diff -ur --new-file old/linux/drivers/char/rocket_int.h new/linux/drivers/char/rocket_int.h --- old/linux/drivers/char/rocket_int.h Fri Jul 10 19:48:37 1998 +++ new/linux/drivers/char/rocket_int.h Wed May 12 22:27:37 1999 @@ -1144,8 +1144,8 @@ struct termios normal_termios; struct termios callout_termios; struct tq_struct tqueue; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; }; #define RPORT_MAGIC 0x525001 diff -ur --new-file old/linux/drivers/char/rtc.c new/linux/drivers/char/rtc.c --- old/linux/drivers/char/rtc.c Fri Jan 15 07:58:47 1999 +++ new/linux/drivers/char/rtc.c Tue May 11 23:37:40 1999 @@ -69,7 +69,7 @@ * ioctls. */ -static struct wait_queue *rtc_wait; +static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); static struct timer_list rtc_irq_timer; @@ -150,7 +150,7 @@ static ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long data; ssize_t retval; @@ -567,7 +567,6 @@ #endif init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; - rtc_wait = NULL; save_flags(flags); cli(); /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ diff -ur --new-file old/linux/drivers/char/selection.c new/linux/drivers/char/selection.c --- old/linux/drivers/char/selection.c Thu Sep 17 18:35:03 1998 +++ new/linux/drivers/char/selection.c Tue May 11 23:37:40 1999 @@ -296,7 +296,7 @@ { struct vt_struct *vt = (struct vt_struct *) tty->driver_data; int pasted = 0, count; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); poke_blanked_console(); add_wait_queue(&vt->paste_wait, &wait); diff -ur --new-file old/linux/drivers/char/serial.c new/linux/drivers/char/serial.c --- old/linux/drivers/char/serial.c Tue Mar 23 22:13:58 1999 +++ new/linux/drivers/char/serial.c Thu May 13 23:52:15 1999 @@ -225,7 +225,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int serial_paranoia_check(struct async_struct *info, kdev_t device, const char *routine) @@ -2422,7 +2422,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct async_struct *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct serial_state *state = info->state; int retval; int do_clocal = 0, extra_count = 0; @@ -2571,6 +2571,9 @@ return -ENOMEM; } memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); info->magic = SERIAL_MAGIC; info->port = sstate->port; info->flags = sstate->flags; diff -ur --new-file old/linux/drivers/char/serial167.c new/linux/drivers/char/serial167.c --- old/linux/drivers/char/serial167.c Thu Nov 5 18:58:43 1998 +++ new/linux/drivers/char/serial167.c Sun May 16 00:05:36 1999 @@ -2007,7 +2007,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, struct cyclades_port *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int channel; int retval; diff -ur --new-file old/linux/drivers/char/specialix.c new/linux/drivers/char/specialix.c --- old/linux/drivers/char/specialix.c Sun May 2 18:51:09 1999 +++ new/linux/drivers/char/specialix.c Wed May 12 22:27:37 1999 @@ -182,7 +182,7 @@ static struct termios * specialix_termios[SX_NBOARD * SX_NPORT] = { NULL, }; static struct termios * specialix_termios_locked[SX_NBOARD * SX_NPORT] = { NULL, }; static unsigned char * tmp_buf = NULL; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static unsigned long baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, @@ -1311,7 +1311,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct specialix_port *port) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct specialix_board *bp = port_Board(port); int retval; int do_clocal = 0; @@ -2248,6 +2248,8 @@ sx_port[i].tqueue_hangup.data = &sx_port[i]; sx_port[i].close_delay = 50 * HZ/100; sx_port[i].closing_wait = 3000 * HZ/100; + init_waitqueue_head(&sx_port[i].open_wait); + init_waitqueue_head(&sx_port[i].close_wait); } return 0; diff -ur --new-file old/linux/drivers/char/specialix_io8.h new/linux/drivers/char/specialix_io8.h --- old/linux/drivers/char/specialix_io8.h Thu Oct 29 07:04:05 1998 +++ new/linux/drivers/char/specialix_io8.h Wed May 12 22:27:37 1999 @@ -122,8 +122,8 @@ int xmit_cnt; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; struct tq_struct tqueue; struct tq_struct tqueue_hangup; short wakeup_chars; diff -ur --new-file old/linux/drivers/char/synclink.c new/linux/drivers/char/synclink.c --- old/linux/drivers/char/synclink.c Sun Mar 28 20:31:31 1999 +++ new/linux/drivers/char/synclink.c Wed May 12 22:27:37 1999 @@ -241,11 +241,11 @@ int xmit_tail; int xmit_cnt; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; - struct wait_queue *status_event_wait_q; - struct wait_queue *event_wait_q; + wait_queue_head_t status_event_wait_q; + wait_queue_head_t event_wait_q; struct timer_list tx_timer; /* HDLC transmit timeout timer */ struct mgsl_struct *next_device; /* device list link */ @@ -904,7 +904,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int mgsl_paranoia_check(struct mgsl_struct *info, kdev_t device, const char *routine) @@ -2724,7 +2724,7 @@ if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->event_wait_q) { + if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ regval = usc_InReg(info,RICR); usc_OutReg(info, RICR, regval & @@ -3295,7 +3295,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct mgsl_struct *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; @@ -4152,6 +4152,10 @@ info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->status_event_wait_q); + init_waitqueue_head(&info->event_wait_q); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; diff -ur --new-file old/linux/drivers/char/tpqic02.c new/linux/drivers/char/tpqic02.c --- old/linux/drivers/char/tpqic02.c Thu Mar 11 01:51:35 1999 +++ new/linux/drivers/char/tpqic02.c Wed May 12 22:27:37 1999 @@ -127,7 +127,7 @@ static volatile int ctlbits = 0; /* control reg bits for tape interface */ -static struct wait_queue *qic02_tape_transfer = NULL; /* sync rw with interrupts */ +static wait_queue_t qic02_tape_transfer; /* sync rw with interrupts */ static volatile struct mtget ioctl_status; /* current generic status */ @@ -2936,6 +2936,7 @@ return -ENODEV; } + init_waitqueue_head(&qic02_tape_transfer); /* prepare timer */ TIMEROFF; timer_table[QIC02_TAPE_TIMER].expires = 0; diff -ur --new-file old/linux/drivers/char/tty_io.c new/linux/drivers/char/tty_io.c --- old/linux/drivers/char/tty_io.c Mon Mar 22 19:06:21 1999 +++ new/linux/drivers/char/tty_io.c Tue May 11 23:37:40 1999 @@ -729,7 +729,7 @@ } /* Semaphore to protect creating and releasing a tty */ -static struct semaphore tty_sem = MUTEX; +static DECLARE_MUTEX(tty_sem); static void down_tty_sem(int index) { @@ -1930,7 +1930,9 @@ tty->flip.flag_buf_ptr = tty->flip.flag_buf; tty->flip.tqueue.routine = flush_to_ldisc; tty->flip.tqueue.data = tty; - tty->flip.pty_sem = MUTEX; + init_MUTEX(&tty->flip.pty_sem); + init_waitqueue_head(&tty->write_wait); + init_waitqueue_head(&tty->read_wait); tty->tq_hangup.routine = do_tty_hangup; tty->tq_hangup.data = tty; sema_init(&tty->atomic_read, 1); diff -ur --new-file old/linux/drivers/char/tty_ioctl.c new/linux/drivers/char/tty_ioctl.c --- old/linux/drivers/char/tty_ioctl.c Tue Jan 19 19:12:05 1999 +++ new/linux/drivers/char/tty_ioctl.c Tue May 11 23:37:40 1999 @@ -42,7 +42,7 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); #ifdef TTY_DEBUG_WAIT_UNTIL_SENT char buf[64]; diff -ur --new-file old/linux/drivers/char/vt.c new/linux/drivers/char/vt.c --- old/linux/drivers/char/vt.c Thu Feb 4 07:57:41 1999 +++ new/linux/drivers/char/vt.c Tue May 11 23:37:40 1999 @@ -1099,7 +1099,7 @@ * while those not ready go back to sleep. Seems overkill to add a wait * to each vt just for this - usually this does nothing! */ -static struct wait_queue *vt_activate_queue = NULL; +static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); /* * Sleeps until a vt is activated, or the task is interrupted. Returns @@ -1108,7 +1108,7 @@ int vt_waitactive(int vt) { int retval; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); add_wait_queue(&vt_activate_queue, &wait); for (;;) { diff -ur --new-file old/linux/drivers/fc4/fc.c new/linux/drivers/fc4/fc.c --- old/linux/drivers/fc4/fc.c Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/fc4/fc.c Wed May 12 17:41:15 1999 @@ -551,7 +551,7 @@ l->magic = LSMAGIC; l->count = count; FCND(("FCP Init for %d channels\n", count)) - l->sem = MUTEX_LOCKED; + init_MUTEX_LOCKED(&l->sem); l->timer.function = fcp_login_timeout; l->timer.data = (unsigned long)l; atomic_set (&l->todo, count); @@ -672,7 +672,7 @@ l.count = count; l.magic = LSOMAGIC; FCND(("FCP Force Offline for %d channels\n", count)) - l.sem = MUTEX_LOCKED; + init_MUTEX_LOCKED(&l.sem); l.timer.function = fcp_login_timeout; l.timer.data = (unsigned long)&l; atomic_set (&l.todo, count); @@ -933,7 +933,7 @@ fcp_cmd *cmd; fcp_cmnd *fcmd; fc_channel *fc = FC_SCMND(SCpnt); - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); if (!fc->rst_pkt) { fc->rst_pkt = (Scsi_Cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL); @@ -1070,7 +1070,7 @@ memset (&l, 0, sizeof(lse)); l.magic = LSEMAGIC; - l.sem = MUTEX_LOCKED; + init_MUTEX_LOCKED(&l.sem); l.timer.function = fcp_login_timeout; l.timer.data = (unsigned long)&l; l.status = FC_STATUS_TIMED_OUT; diff -ur --new-file old/linux/drivers/isdn/avmb1/capidev.h new/linux/drivers/isdn/avmb1/capidev.h --- old/linux/drivers/isdn/avmb1/capidev.h Fri May 30 06:53:05 1997 +++ new/linux/drivers/isdn/avmb1/capidev.h Sun May 16 00:05:36 1999 @@ -22,7 +22,7 @@ int is_registered; __u16 applid; struct sk_buff_head recv_queue; - struct wait_queue *recv_wait; + wait_queue_head_t recv_wait; __u16 errcode; }; diff -ur --new-file old/linux/drivers/isdn/isdn_common.c new/linux/drivers/isdn/isdn_common.c --- old/linux/drivers/isdn/isdn_common.c Tue Jan 19 20:06:52 1999 +++ new/linux/drivers/isdn/isdn_common.c Thu May 13 19:53:38 1999 @@ -741,7 +741,6 @@ isdn_free_queue(&dev->drv[di]->rpqueue[i]); kfree(dev->drv[di]->rpqueue); kfree(dev->drv[di]->rcv_waitq); - kfree(dev->drv[di]->snd_waitq); kfree(dev->drv[di]); dev->drv[di] = NULL; dev->drvid[di][0] = '\0'; @@ -785,7 +784,7 @@ * of the mapping (di,ch)<->minor, happen during the sleep? --he */ int -isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep) +isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep) { int left; int count; @@ -2088,6 +2087,7 @@ return 0; } memset((char *) d, 0, sizeof(driver)); + init_waitqueue_head(&d->st_waitq); if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); kfree(d); @@ -2112,8 +2112,9 @@ for (j = 0; j < n; j++) { skb_queue_head_init(&d->rpqueue[j]); } - if (!(d->rcv_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { + d->rcv_waitq = (wait_queue_head_t *) + kmalloc(sizeof(wait_queue_head_t) * 2 * n, GFP_KERNEL); + if (!d->rcv_waitq) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); kfree(d->rpqueue); kfree(d->rcvcount); @@ -2121,18 +2122,11 @@ kfree(d); return 0; } - memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * n); - if (!(d->snd_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n"); - kfree(d->rcv_waitq); - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; + d->snd_waitq = d->rcv_waitq + n; + for (j = 0; j < n; j++) { + init_waitqueue_head(&d->rcv_waitq[n]); + init_waitqueue_head(&d->snd_waitq[n]); } - memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * n); d->channels = n; d->loaded = 1; d->maxbufsize = i->maxbufsize; @@ -2215,12 +2209,15 @@ memset((char *) dev, 0, sizeof(isdn_dev)); init_timer(&dev->timer); dev->timer.function = isdn_timer_funct; - dev->sem = MUTEX; + init_MUTEX(&dev->sem); + init_waitqueue_head(&dev->info_waitq); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; dev->m_idx[i] = -1; strcpy(dev->num[i], "???"); + init_waitqueue_head(&dev->mdm.info[i].open_wait); + init_waitqueue_head(&dev->mdm.info[i].close_wait); } if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { printk(KERN_WARNING "isdn: Could not register control devices\n"); diff -ur --new-file old/linux/drivers/isdn/isdn_common.h new/linux/drivers/isdn/isdn_common.h --- old/linux/drivers/isdn/isdn_common.h Tue Jan 19 20:06:52 1999 +++ new/linux/drivers/isdn/isdn_common.h Thu May 13 19:53:42 1999 @@ -90,7 +90,7 @@ extern void isdn_timer_ctrl(int tf, int onoff); extern void isdn_unexclusive_channel(int di, int ch); extern int isdn_getnum(char **); -extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**); +extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); extern int isdn_get_free_channel(int, int, int, int, int); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); diff -ur --new-file old/linux/drivers/isdn/isdn_ppp.c new/linux/drivers/isdn/isdn_ppp.c --- old/linux/drivers/isdn/isdn_ppp.c Tue Jan 19 20:06:52 1999 +++ new/linux/drivers/isdn/isdn_ppp.c Thu May 13 19:53:46 1999 @@ -359,8 +359,7 @@ ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; - if (ippp_table[lp->ppp_slot]->wq) - wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); + wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); } /* @@ -377,7 +376,7 @@ return 0; is = ippp_table[slot]; - if (is->state && is->wq) + if (is->state) wake_up_interruptible(&is->wq); is->state = IPPP_CLOSEWAIT; @@ -437,8 +436,9 @@ is->mru = 1524; /* MRU, default 1524 */ is->maxcid = 16; /* VJ: maxcid */ is->tk = current; - is->wq = NULL; /* read() wait queue */ - is->wq1 = NULL; /* select() wait queue */ + /* next two are redundant, but be paranoid */ + init_waitqueue_head(&is->wq); /* read() wait queue */ + init_waitqueue_head(&is->wql); /* select() wait queue */ is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; is->minor = min; @@ -777,8 +777,7 @@ is->last = bl->next; restore_flags(flags); - if (is->wq) - wake_up_interruptible(&is->wq); + wake_up_interruptible(&is->wq); return len; } @@ -911,6 +910,8 @@ return -1; } memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); + init_waitqueue_head(&ippp_table[i]->wq); + init_waitqueue_head(&ippp_table[i]->wql); ippp_table[i]->state = 0; ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; ippp_table[i]->last = ippp_table[i]->rq; diff -ur --new-file old/linux/drivers/isdn/isdn_tty.c new/linux/drivers/isdn/isdn_tty.c --- old/linux/drivers/isdn/isdn_tty.c Sat Oct 31 19:37:14 1998 +++ new/linux/drivers/isdn/isdn_tty.c Thu May 13 19:53:50 1999 @@ -1567,8 +1567,7 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info) { - struct wait_queue wait = - {current, NULL}; + DECLARE_WAITQUEUE(wait, current); int do_clocal = 0; unsigned long flags; int retval; @@ -2004,8 +2003,8 @@ info->blocked_open = 0; info->callout_termios = m->cua_modem.init_termios; info->normal_termios = m->tty_modem.init_termios; - info->open_wait = 0; - info->close_wait = 0; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); info->isdn_driver = -1; info->isdn_channel = -1; info->drv_index = -1; diff -ur --new-file old/linux/drivers/isdn/pcbit/pcbit.h new/linux/drivers/isdn/pcbit/pcbit.h --- old/linux/drivers/isdn/pcbit/pcbit.h Tue Aug 4 19:31:59 1998 +++ new/linux/drivers/isdn/pcbit/pcbit.h Sun May 16 00:05:36 1999 @@ -68,7 +68,7 @@ struct frame_buf *write_queue; /* Protocol start */ - struct wait_queue *set_running_wq; + wait_queue_head_t set_running_wq; struct timer_list set_running_timer; struct timer_list error_recover_timer; diff -ur --new-file old/linux/drivers/macintosh/adb.c new/linux/drivers/macintosh/adb.c --- old/linux/drivers/macintosh/adb.c Thu Apr 29 21:53:48 1999 +++ new/linux/drivers/macintosh/adb.c Sun May 16 00:05:36 1999 @@ -375,7 +375,7 @@ spinlock_t lock; atomic_t n_pending; struct adb_request *completed; - struct wait_queue *wait_queue; + wait_queue_head_t wait_queue; int inuse; }; @@ -458,7 +458,7 @@ int ret; struct adbdev_state *state = file->private_data; struct adb_request *req; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; if (count < 2) diff -ur --new-file old/linux/drivers/macintosh/mac_keyb.c new/linux/drivers/macintosh/mac_keyb.c --- old/linux/drivers/macintosh/mac_keyb.c Thu Apr 29 21:53:48 1999 +++ new/linux/drivers/macintosh/mac_keyb.c Sun May 16 00:05:36 1999 @@ -251,7 +251,7 @@ extern int console_loglevel; extern struct kbd_struct kbd_table[]; -extern struct wait_queue * keypress_wait; +extern struct wait_queue_head_t keypress_wait; extern void handle_scancode(unsigned char, int); diff -ur --new-file old/linux/drivers/macintosh/macserial.c new/linux/drivers/macintosh/macserial.c --- old/linux/drivers/macintosh/macserial.c Thu Apr 29 21:53:48 1999 +++ new/linux/drivers/macintosh/macserial.c Sun May 16 00:05:36 1999 @@ -1595,7 +1595,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct mac_serial *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait,current); int retval; int do_clocal = 0; diff -ur --new-file old/linux/drivers/macintosh/macserial.h new/linux/drivers/macintosh/macserial.h --- old/linux/drivers/macintosh/macserial.h Thu Mar 11 06:48:46 1999 +++ new/linux/drivers/macintosh/macserial.h Sun May 16 00:05:36 1999 @@ -153,8 +153,8 @@ struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; }; diff -ur --new-file old/linux/drivers/misc/parport_init.c new/linux/drivers/misc/parport_init.c --- old/linux/drivers/misc/parport_init.c Tue May 11 18:55:49 1999 +++ new/linux/drivers/misc/parport_init.c Sun May 16 19:55:21 1999 @@ -20,10 +20,11 @@ #ifndef MODULE static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; +static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY }; static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; -extern int parport_pc_init(int *io, int *irq, int *dma); +extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); extern int parport_ax_init(void); static int parport_setup_ptr __initdata = 0; @@ -121,7 +122,7 @@ parport_proc_init(); #endif #ifdef CONFIG_PARPORT_PC - parport_pc_init(io, irq, dma); + parport_pc_init(io, io_hi, irq, dma); #endif #ifdef CONFIG_PARPORT_AX parport_ax_init(); diff -ur --new-file old/linux/drivers/misc/parport_pc.c new/linux/drivers/misc/parport_pc.c --- old/linux/drivers/misc/parport_pc.c Mon May 10 19:26:31 1999 +++ new/linux/drivers/misc/parport_pc.c Sun May 16 19:10:00 1999 @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,7 @@ than PARPORT_MAX (in ). */ #define PARPORT_PC_MAX_PORTS 8 -static int user_specified = 0; +static int user_specified __initdata = 0; static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -62,27 +63,27 @@ void parport_pc_write_epp(struct parport *p, unsigned char d) { - outb(d, p->base+EPPDATA); + outb(d, EPPDATA(p)); } unsigned char parport_pc_read_epp(struct parport *p) { - return inb(p->base+EPPDATA); + return inb(EPPDATA(p)); } void parport_pc_write_epp_addr(struct parport *p, unsigned char d) { - outb(d, p->base+EPPADDR); + outb(d, EPPADDR(p)); } unsigned char parport_pc_read_epp_addr(struct parport *p) { - return inb(p->base+EPPADDR); + return inb(EPPADDR(p)); } int parport_pc_check_epp_timeout(struct parport *p) { - if (!(inb(p->base+STATUS) & 1)) + if (!(inb(STATUS(p)) & 1)) return 0; parport_pc_epp_clear_timeout(p); return 1; @@ -90,24 +91,24 @@ unsigned char parport_pc_read_configb(struct parport *p) { - return inb(p->base+CONFIGB); + return inb(CONFIGB(p)); } void parport_pc_write_data(struct parport *p, unsigned char d) { - outb(d, p->base+DATA); + outb(d, DATA(p)); } unsigned char parport_pc_read_data(struct parport *p) { - return inb(p->base+DATA); + return inb(DATA(p)); } void parport_pc_write_control(struct parport *p, unsigned char d) { struct parport_pc_private *priv = p->private_data; priv->ctr = d;/* update soft copy */ - outb(d, p->base+CONTROL); + outb(d, CONTROL(p)); } unsigned char parport_pc_read_control(struct parport *p) @@ -121,34 +122,34 @@ struct parport_pc_private *priv = p->private_data; unsigned char ctr = priv->ctr; ctr = (ctr & ~mask) ^ val; - outb (ctr, p->base+CONTROL); + outb (ctr, CONTROL(p)); return priv->ctr = ctr; /* update soft copy */ } void parport_pc_write_status(struct parport *p, unsigned char d) { - outb(d, p->base+STATUS); + outb(d, STATUS(p)); } unsigned char parport_pc_read_status(struct parport *p) { - return inb(p->base+STATUS); + return inb(STATUS(p)); } void parport_pc_write_econtrol(struct parport *p, unsigned char d) { - outb(d, p->base+ECONTROL); + outb(d, ECONTROL(p)); } unsigned char parport_pc_read_econtrol(struct parport *p) { - return inb(p->base+ECONTROL); + return inb(ECONTROL(p)); } unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned char old = inb(p->base+ECONTROL); - outb(((old & ~mask) ^ val), p->base+ECONTROL); + unsigned char old = inb(ECONTROL(p)); + outb(((old & ~mask) ^ val), ECONTROL(p)); return old; } @@ -159,12 +160,12 @@ void parport_pc_write_fifo(struct parport *p, unsigned char v) { - outb (v, p->base+CONFIGA); + outb (v, CONFIGA(p)); } unsigned char parport_pc_read_fifo(struct parport *p) { - return inb (p->base+CONFIGA); + return inb (CONFIGA(p)); } void parport_pc_disable_irq(struct parport *p) @@ -183,7 +184,7 @@ free_irq(p->irq, p); release_region(p->base, p->size); if (p->modes & PARPORT_MODE_PCECR) - release_region(p->base+0x400, 3); + release_region(p->base_hi, 3); } int parport_pc_claim_resources(struct parport *p) @@ -195,7 +196,7 @@ return err; request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) - request_region(p->base+0x400, 3, p->name); + request_region(p->base_hi, 3, p->name); return 0; } @@ -223,8 +224,8 @@ { size_t got = 0; for (; got < length; got++) { - *((char*)buf)++ = inb (p->base+EPPDATA); - if (inb (p->base+STATUS) & 0x01) + *((char*)buf)++ = inb (EPPDATA(p)); + if (inb (STATUS(p)) & 0x01) break; } return got; @@ -234,8 +235,8 @@ { size_t written = 0; for (; written < length; written++) { - outb (*((char*)buf)++, p->base+EPPDATA); - if (inb (p->base+STATUS) & 0x01) + outb (*((char*)buf)++, EPPDATA(p)); + if (inb (STATUS(p)) & 0x01) break; } return written; @@ -350,7 +351,7 @@ /* * Checks for port existence, all ports support SPP MODE */ -static int parport_SPP_supported(struct parport *pb) +static int __init parport_SPP_supported(struct parport *pb) { unsigned char r, w; @@ -370,11 +371,11 @@ * allow reads, so read_control just returns a software * copy. Some ports _do_ allow reads, so bypass the software * copy here. In addition, some bits aren't writable. */ - r = inb (pb->base+CONTROL); + r = inb (CONTROL (pb)); if ((r & 0x3f) == w) { w = 0xe; parport_pc_write_control (pb, w); - r = inb (pb->base+CONTROL); + r = inb (CONTROL(pb)); parport_pc_write_control (pb, 0xc); if ((r & 0x3f) == w) return PARPORT_MODE_PCSPP; @@ -425,7 +426,7 @@ * We will write 0x2c to ECR and 0xcc to CTR since both of these * values are "safe" on the CTR since bits 6-7 of CTR are unused. */ -static int parport_ECR_present(struct parport *pb) +static int __init parport_ECR_present(struct parport *pb) { unsigned char r; @@ -458,7 +459,7 @@ return 0; } -static int parport_ECP_supported(struct parport *pb) +static int __init parport_ECP_supported(struct parport *pb) { int i; unsigned char oecr; @@ -493,7 +494,7 @@ * or writing a 1 to the bit (SMC, UMC, WinBond), others ??? * This bit is always high in non EPP modes. */ -static int parport_EPP_supported(struct parport *pb) +static int __init parport_EPP_supported(struct parport *pb) { /* If EPP timeout bit clear then EPP available */ if (!parport_pc_epp_clear_timeout(pb)) @@ -514,7 +515,7 @@ return 0; } -static int parport_ECPEPP_supported(struct parport *pb) +static int __init parport_ECPEPP_supported(struct parport *pb) { int mode; unsigned char oecr; @@ -550,7 +551,7 @@ * be misdetected here is rather academic. */ -static int parport_PS2_supported(struct parport *pb) +static int __init parport_PS2_supported(struct parport *pb) { int ok = 0; unsigned char octr = parport_pc_read_control(pb); @@ -570,7 +571,7 @@ return ok?PARPORT_MODE_PCPS2:0; } -static int parport_ECPPS2_supported(struct parport *pb) +static int __init parport_ECPPS2_supported(struct parport *pb) { int mode; unsigned char oecr; @@ -590,7 +591,7 @@ /* --- IRQ detection -------------------------------------- */ /* Only if supports ECP mode */ -static int programmable_irq_support(struct parport *pb) +static int __init programmable_irq_support(struct parport *pb) { int irq, intrLine; unsigned char oecr = parport_pc_read_econtrol(pb); @@ -607,7 +608,7 @@ return irq; } -static int irq_probe_ECP(struct parport *pb) +static int __init irq_probe_ECP(struct parport *pb) { int irqs, i; @@ -634,7 +635,7 @@ * This detection seems that only works in National Semiconductors * This doesn't work in SMC, LGS, and Winbond */ -static int irq_probe_EPP(struct parport *pb) +static int __init irq_probe_EPP(struct parport *pb) { int irqs; unsigned char octr = parport_pc_read_control(pb); @@ -675,7 +676,7 @@ return pb->irq; } -static int irq_probe_SPP(struct parport *pb) +static int __init irq_probe_SPP(struct parport *pb) { int irqs; unsigned char octr = parport_pc_read_control(pb); @@ -723,7 +724,7 @@ * When ECP is available we can autoprobe for IRQs. * NOTE: If we can autoprobe it, we can register the IRQ. */ -static int parport_irq_probe(struct parport *pb) +static int __init parport_irq_probe(struct parport *pb) { if (pb->modes & PARPORT_MODE_PCECR) { pb->irq = programmable_irq_support(pb); @@ -754,7 +755,9 @@ /* --- Initialisation code -------------------------------- */ -static int probe_one_port(unsigned long int base, int irq, int dma) +static int __init probe_one_port(unsigned long int base, + unsigned long int base_hi, + int irq, int dma) { struct parport *p; int probedirq = PARPORT_IRQ_NONE; @@ -770,8 +773,9 @@ return 0; } ((struct parport_pc_private *) (p->private_data))->ctr = 0xc; + p->base_hi = base_hi; if (p->base != 0x3bc) { - if (!check_region(base+0x400,3)) { + if (base_hi && !check_region(base_hi,3)) { p->modes |= parport_ECR_present(p); p->modes |= parport_ECP_supported(p); p->modes |= parport_ECPPS2_supported(p); @@ -791,6 +795,8 @@ p->size = (p->modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP))?8:3; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); + if (p->base_hi && (p->modes & PARPORT_MODE_PCECR)) + printk (" (0x%lx)", p->base_hi); if (p->irq == PARPORT_IRQ_AUTO) { p->irq = PARPORT_IRQ_NONE; parport_irq_probe(p); @@ -829,11 +835,14 @@ /* Done probing. Now put the port into a sensible start-up state. */ if (p->modes & PARPORT_MODE_PCECR) /* - * Put the ECP detected port in the more SPP like mode. + * Put the ECP detected port in PS2 mode. */ - parport_pc_write_econtrol(p, 0x0); - parport_pc_write_control(p, 0xc); + parport_pc_write_econtrol(p, 0x24); parport_pc_write_data(p, 0); + parport_pc_write_control(p, 0x8); + udelay (50); + parport_pc_write_control(p, 0xc); + udelay (50); if (parport_probe_hook) (*parport_probe_hook)(p); @@ -841,20 +850,22 @@ return 1; } -int parport_pc_init(int *io, int *irq, int *dma) +int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma) { int count = 0, i = 0; if (io && *io) { /* Only probe the ports we were given. */ user_specified = 1; do { - count += probe_one_port(*(io++), *(irq++), *(dma++)); + if (!*io_hi) *io_hi = 0x400 + *io; + count += probe_one_port(*(io++), *(io_hi++), + *(irq++), *(dma++)); } while (*io && (++i < PARPORT_PC_MAX_PORTS)); } else { /* Probe all the likely ports. */ - count += probe_one_port(0x3bc, irq[0], dma[0]); - count += probe_one_port(0x378, irq[0], dma[0]); - count += probe_one_port(0x278, irq[0], dma[0]); + count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]); + count += probe_one_port(0x378, 0x778, irq[0], dma[0]); + count += probe_one_port(0x278, 0x678, irq[0], dma[0]); } return count; @@ -862,10 +873,12 @@ #ifdef MODULE static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; +static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE }; static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); +MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); @@ -877,7 +890,7 @@ for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); parport_parse_irqs(i, irq, irqval); - return (parport_pc_init(io, irqval, dma)?0:1); + return (parport_pc_init(io, io_hi, irqval, dma)?0:1); } void cleanup_module(void) diff -ur --new-file old/linux/drivers/misc/parport_share.c new/linux/drivers/misc/parport_share.c --- old/linux/drivers/misc/parport_share.c Tue Oct 27 19:32:29 1998 +++ new/linux/drivers/misc/parport_share.c Wed May 12 08:38:24 1999 @@ -277,7 +277,7 @@ inc_parport_count(); port->ops->inc_use_count(); - init_waitqueue(&tmp->wait_q); + init_waitqueue_head(&tmp->wait_q); tmp->timeslice = PARPORT_DEFAULT_TIMESLICE; tmp->waitnext = tmp->waitprev = NULL; diff -ur --new-file old/linux/drivers/net/3c527.c new/linux/drivers/net/3c527.c --- old/linux/drivers/net/3c527.c Sun Mar 21 16:11:36 1999 +++ new/linux/drivers/net/3c527.c Wed May 12 22:27:37 1999 @@ -102,7 +102,7 @@ u16 exec_pending; u16 mc_reload_wait; /* a multicast load request is pending */ atomic_t tx_count; /* buffers left */ - struct wait_queue *event; + wait_queue_head_t event; struct sk_buff *tx_skb[TX_RING_MAX]; /* Transmit ring */ u16 tx_skb_top; u16 tx_skb_end; @@ -411,6 +411,7 @@ lp->rx_chain = lp->exec_box->data[10]; lp->tx_len = lp->exec_box->data[9]; lp->rx_len = lp->exec_box->data[11]; + init_waitqueue_head(&lp->event); printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->rx_len, lp->tx_len, lp->base); diff -ur --new-file old/linux/drivers/net/cosa.c new/linux/drivers/net/cosa.c --- old/linux/drivers/net/cosa.c Mon Mar 8 00:47:46 1999 +++ new/linux/drivers/net/cosa.c Sun May 16 00:05:36 1999 @@ -126,7 +126,8 @@ struct semaphore rsem, wsem; char *rxdata; int rxsize; - struct wait_queue *txwaitq, *rxwaitq; + wait_queue_head_t txwaitq; + wait_queue_head_t rxwaitq; int tx_status, rx_status; /* SPPP/HDLC device parts */ @@ -762,7 +763,7 @@ static ssize_t cosa_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int flags; struct channel_data *chan = (struct channel_data *)file->private_data; struct cosa_data *cosa = chan->cosa; @@ -833,7 +834,7 @@ const char *buf, size_t count, loff_t *ppos) { struct channel_data *chan = (struct channel_data *)file->private_data; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct cosa_data *cosa = chan->cosa; unsigned int flags; char *kbuf; diff -ur --new-file old/linux/drivers/net/de620.c new/linux/drivers/net/de620.c --- old/linux/drivers/net/de620.c Mon Mar 2 20:55:41 1998 +++ new/linux/drivers/net/de620.c Sun May 16 08:43:04 1999 @@ -664,7 +664,7 @@ if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) { /* Ouch... Forget it! Skip all and start afresh... */ printk("%s: Ring overrun? Restoring...\n", dev->name); - /* You win some, you loose some. And sometimes plenty... */ + /* You win some, you lose some. And sometimes plenty... */ adapter_init(dev); ((struct net_device_stats *)(dev->priv))->rx_over_errors++; return 0; diff -ur --new-file old/linux/drivers/net/ibmtr.c new/linux/drivers/net/ibmtr.c --- old/linux/drivers/net/ibmtr.c Fri May 7 19:57:42 1999 +++ new/linux/drivers/net/ibmtr.c Wed May 12 22:27:37 1999 @@ -404,6 +404,8 @@ #endif ti->mmio= t_mmio; ti->readlog_pending = 0; + init_waitqueue_head(&ti->wait_for_tok_int); + init_waitqueue_head(&ti->wait_for_reset); dev->priv = ti; /* this seems like the logical use of the field ... let's try some empirical tests diff -ur --new-file old/linux/drivers/net/ibmtr.h new/linux/drivers/net/ibmtr.h --- old/linux/drivers/net/ibmtr.h Tue Mar 16 23:21:52 1999 +++ new/linux/drivers/net/ibmtr.h Wed May 12 22:27:37 1999 @@ -193,8 +193,8 @@ unsigned short maxmtu16; /* Additions by David Morris */ unsigned char do_tok_int; - struct wait_queue *wait_for_tok_int; - struct wait_queue *wait_for_reset; + wait_queue_head_t wait_for_tok_int; + wait_queue_head_t wait_for_reset; unsigned char sram_base; /* Additions by Peter De Schrijver */ unsigned char page_mask; /* mask to select RAM page to Map*/ diff -ur --new-file old/linux/drivers/net/ppp.c new/linux/drivers/net/ppp.c --- old/linux/drivers/net/ppp.c Tue May 11 18:55:45 1999 +++ new/linux/drivers/net/ppp.c Wed May 12 17:41:15 1999 @@ -2834,7 +2834,7 @@ ppp->magic = PPP_MAGIC; ppp->next = NULL; ppp->inuse = 1; - ppp->read_wait = NULL; + init_waitqueue_head(&ppp->read_wait); /* * Make up a suitable name for this device diff -ur --new-file old/linux/drivers/net/shaper.c new/linux/drivers/net/shaper.c --- old/linux/drivers/net/shaper.c Thu Mar 11 01:51:35 1999 +++ new/linux/drivers/net/shaper.c Wed May 12 22:27:37 1999 @@ -582,6 +582,7 @@ init_timer(&sh->timer); sh->timer.function=shaper_timer; sh->timer.data=(unsigned long)sh; + init_waitqueue_head(&sh->wait_queue); return sh; } diff -ur --new-file old/linux/drivers/net/sktr.c new/linux/drivers/net/sktr.c --- old/linux/drivers/net/sktr.c Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/net/sktr.c Wed May 12 22:27:37 1999 @@ -414,7 +414,8 @@ if(tp == NULL) return (-ENOMEM); memset(tp, 0, sizeof(struct net_local)); - + init_waitqueue_head(&tp->wait_for_tok_int); + dev->priv = tp; dev->init = sktr_init_card; dev->open = sktr_open; diff -ur --new-file old/linux/drivers/net/sktr.h new/linux/drivers/net/sktr.h --- old/linux/drivers/net/sktr.h Wed Jun 24 23:26:13 1998 +++ new/linux/drivers/net/sktr.h Wed May 12 22:27:37 1999 @@ -1087,7 +1087,7 @@ struct timer_list timer; - struct wait_queue *wait_for_tok_int; + wait_queue_head_t wait_for_tok_int; INTPTRS intptrs; /* Internal adapter pointer. Must be read * before OPEN command. diff -ur --new-file old/linux/drivers/net/sunhme.c new/linux/drivers/net/sunhme.c --- old/linux/drivers/net/sunhme.c Tue Mar 16 01:11:30 1999 +++ new/linux/drivers/net/sunhme.c Sat May 15 20:12:09 1999 @@ -1834,7 +1834,7 @@ #define RXD(x) #endif -/* Originally I use to handle the allocation failure by just giving back just +/* Originally I used to handle the allocation failure by just giving back just * that one ring buffer to the happy meal. Problem is that usually when that * condition is triggered, the happy meal expects you to do something reasonable * with all of the packets it has DMA'd in. So now I just drop the entire diff -ur --new-file old/linux/drivers/net/z85230.h new/linux/drivers/net/z85230.h --- old/linux/drivers/net/z85230.h Sun Oct 18 00:33:45 1998 +++ new/linux/drivers/net/z85230.h Sun May 16 00:05:36 1999 @@ -331,8 +331,8 @@ int line; /* Minor number */ struct termios normal_termios; /* Terminal settings */ struct termios callout_termios; - struct wait_queue *open_wait; /* Tasks waiting to open */ - struct wait_queue *close_wait; /* and for close to end */ + wait_queue_head_t open_wait; /* Tasks waiting to open */ + wait_queue_head_t close_wait; /* and for close to end */ unsigned long event; /* Pending events */ int fdcount; /* # of fd on device */ int blocked_open; /* # of blocked opens */ diff -ur --new-file old/linux/drivers/pci/oldproc.c new/linux/drivers/pci/oldproc.c --- old/linux/drivers/pci/oldproc.c Wed Apr 21 18:28:49 1999 +++ new/linux/drivers/pci/oldproc.c Thu May 13 20:00:08 1999 @@ -203,6 +203,7 @@ DEVICE( MOTOROLA, MOTOROLA_MPC106,"MPC106 Grackle"), DEVICE( MOTOROLA, MOTOROLA_RAVEN, "Raven"), DEVICE( PROMISE, PROMISE_20246, "IDE UltraDMA/33"), + DEVICE( PROMISE, PROMISE_20262, "IDE UltraDMA/66"), DEVICE( PROMISE, PROMISE_5300, "DC5030"), DEVICE( N9, N9_I128, "Imagine 128"), DEVICE( N9, N9_I128_2, "Imagine 128v2"), @@ -290,11 +291,15 @@ DEVICE( AL, AL_M1523, "M1523"), DEVICE( AL, AL_M1531, "M1531 Aladdin IV"), DEVICE( AL, AL_M1533, "M1533 Aladdin IV"), + DEVICE( AL, AL_M1541, "M1541 Aladdin V"), + DEVICE( AL, AL_M1543, "M1543 Aladdin V"), 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( AL, AL_M5243, "M5243 AGP"), + DEVICE( AL, AL_M7101, "M7101 PMU"), DEVICE( SURECOM, SURECOM_NE34, "NE-34PCI LAN"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), diff -ur --new-file old/linux/drivers/sbus/audio/audio.c new/linux/drivers/sbus/audio/audio.c --- old/linux/drivers/sbus/audio/audio.c Fri Apr 23 04:24:51 1999 +++ new/linux/drivers/sbus/audio/audio.c Wed May 12 17:41:15 1999 @@ -117,6 +117,11 @@ * TODO: Make number of input/output buffers tunable parameters */ + init_waitqueue_head(&drv->open_wait); + init_waitqueue_head(&drv->output_write_wait); + init_waitqueue_head(&drv->output_drain_wait); + init_waitqueue_head(&drv->input_read_wait); + drv->num_output_buffers = 8; drv->output_buffer_size = (4096 * 2); drv->playing_count = 0; diff -ur --new-file old/linux/drivers/sbus/audio/dbri.h new/linux/drivers/sbus/audio/dbri.h --- old/linux/drivers/sbus/audio/dbri.h Tue Mar 16 01:11:30 1999 +++ new/linux/drivers/sbus/audio/dbri.h Wed May 12 17:41:15 1999 @@ -85,7 +85,7 @@ struct cs4215 mm; /* mmcodec special info */ #if 0 - struct wait_queue *wait, *int_wait; /* Where to sleep if busy */ + wait_queue_head_t wait, int_wait; /* Where to sleep if busy */ #endif struct audio_info perchip_info; diff -ur --new-file old/linux/drivers/sbus/char/bpp.c new/linux/drivers/sbus/char/bpp.c --- old/linux/drivers/sbus/char/bpp.c Tue Mar 16 01:11:30 1999 +++ new/linux/drivers/sbus/char/bpp.c Wed May 12 17:41:15 1999 @@ -81,7 +81,7 @@ unsigned char repeat_byte; /* These members manage timeouts for programmed delays */ - struct wait_queue *wait_queue; + wait_queue_head_t wait_queue; struct timer_list timer_list; }; diff -ur --new-file old/linux/drivers/sbus/char/pcikbd.c new/linux/drivers/sbus/char/pcikbd.c --- old/linux/drivers/sbus/char/pcikbd.c Tue May 11 17:24:32 1999 +++ new/linux/drivers/sbus/char/pcikbd.c Mon May 17 04:15:57 1999 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $ +/* $Id: pcikbd.c,v 1.29 1999/05/16 13:47:53 ecd Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -588,7 +588,7 @@ struct aux_queue { unsigned long head; unsigned long tail; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; struct fasync_struct *fasync; unsigned char buf[AUX_BUF_SIZE]; }; @@ -739,7 +739,7 @@ * doing so might cause the keyboard driver to ignore all incoming keystrokes. */ -static struct semaphore aux_sema4 = MUTEX; +static DECLARE_MUTEX(aux_sema4); static inline void aux_start_atomic(void) { @@ -879,7 +879,7 @@ static ssize_t aux_read(struct file * file, char * buffer, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); ssize_t i = count; unsigned char c; @@ -982,6 +982,8 @@ return -ENOMEM; } memset(queue, 0, sizeof(*queue)); + + init_waitqueue_head(&queue->proc_list); if (request_irq(pcimouse_irq, &pcimouse_interrupt, SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) { diff -ur --new-file old/linux/drivers/sbus/char/sab82532.c new/linux/drivers/sbus/char/sab82532.c --- old/linux/drivers/sbus/char/sab82532.c Thu Mar 25 18:23:34 1999 +++ new/linux/drivers/sbus/char/sab82532.c Wed May 12 17:41:15 1999 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.30 1999/03/24 11:34:52 davem Exp $ +/* $Id: sab82532.c,v 1.31 1999/05/12 11:15:10 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -100,7 +100,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf = 0; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int serial_paranoia_check(struct sab82532 *info, kdev_t device, const char *routine) @@ -1715,7 +1715,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sab82532 *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -2136,7 +2136,7 @@ __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.30 $"; + char *revision = "$Revision: 1.31 $"; char *version, *p; version = strchr(revision, ' '); @@ -2247,9 +2247,9 @@ info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; - info->delta_msr_wait = 0; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); info->icount.cts = info->icount.dsr = info->icount.rng = info->icount.dcd = 0; info->icount.rx = info->icount.tx = 0; diff -ur --new-file old/linux/drivers/sbus/char/su.c new/linux/drivers/sbus/char/su.c --- old/linux/drivers/sbus/char/su.c Tue Mar 16 01:11:30 1999 +++ new/linux/drivers/sbus/char/su.c Wed May 12 17:41:15 1999 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.18 1999/01/02 16:47:37 davem Exp $ +/* $Id: su.c,v 1.19 1999/05/12 11:15:14 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -135,9 +135,9 @@ int xmit_tail; int xmit_cnt; struct tq_struct tqueue; - struct wait_queue *open_wait; - struct wait_queue *close_wait; - struct wait_queue *delta_msr_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t delta_msr_wait; int count; struct async_icount icount; @@ -200,7 +200,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int serial_paranoia_check(struct su_struct *info, kdev_t device, const char *routine) @@ -1878,7 +1878,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, struct su_struct *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; @@ -2215,7 +2215,7 @@ */ __initfunc(static __inline__ void show_su_version(void)) { - char *revision = "$Revision: 1.18 $"; + char *revision = "$Revision: 1.19 $"; char *version, *p; version = strchr(revision, ' '); diff -ur --new-file old/linux/drivers/sbus/char/sunkbd.c new/linux/drivers/sbus/char/sunkbd.c --- old/linux/drivers/sbus/char/sunkbd.c Fri Apr 23 04:24:51 1999 +++ new/linux/drivers/sbus/char/sunkbd.c Wed May 12 17:41:15 1999 @@ -85,7 +85,7 @@ } #ifndef CONFIG_PCI -struct wait_queue * keypress_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(keypress_wait); #endif int keyboard_wait_for_keypress(struct console *co) @@ -1261,7 +1261,7 @@ static int kbd_head, kbd_tail; char kbd_opened; static int kbd_active = 0; -static struct wait_queue *kbd_wait; +static DECLARE_WAIT_QUEUE_HEAD(kbd_wait); static struct fasync_struct *kb_fasync; void @@ -1285,7 +1285,7 @@ static ssize_t kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); char *end, *p; /* Return EWOULDBLOCK, because this is what the X server expects */ diff -ur --new-file old/linux/drivers/sbus/char/sunmouse.c new/linux/drivers/sbus/char/sunmouse.c --- old/linux/drivers/sbus/char/sunmouse.c Fri Apr 23 04:24:51 1999 +++ new/linux/drivers/sbus/char/sunmouse.c Wed May 12 17:41:15 1999 @@ -73,7 +73,7 @@ int ready; /* set if there if data is available */ int active; /* set if device is open */ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ - struct wait_queue *proc_list; + wait_queue_head_t proc_list; struct fasync_struct *fasync; /* The event/stream queue */ @@ -368,7 +368,7 @@ sun_mouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); if (queue_empty ()){ if (file->f_flags & O_NONBLOCK) @@ -503,7 +503,7 @@ misc_register (&sun_mouse_mouse); sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; - sunmouse.proc_list = NULL; + init_waitqueue_head(&sunmouse.proc_list); sunmouse.byte = 69; return 0; } diff -ur --new-file old/linux/drivers/sbus/char/vfc.h new/linux/drivers/sbus/char/vfc.h --- old/linux/drivers/sbus/char/vfc.h Wed May 14 07:41:12 1997 +++ new/linux/drivers/sbus/char/vfc.h Wed May 12 17:41:15 1999 @@ -128,7 +128,7 @@ unsigned int control_reg; struct semaphore device_lock_sem; struct timer_list poll_timer; - struct wait_queue *poll_wait; + wait_queue_head_t poll_wait; int instance; int busy; unsigned long which_io; diff -ur --new-file old/linux/drivers/sbus/char/zs.c new/linux/drivers/sbus/char/zs.c --- old/linux/drivers/sbus/char/zs.c Fri Apr 23 04:24:51 1999 +++ new/linux/drivers/sbus/char/zs.c Wed May 12 17:41:15 1999 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.41 1999/04/16 16:22:27 jj Exp $ +/* $Id: zs.c,v 1.42 1999/05/12 11:15:26 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -174,7 +174,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char tmp_buf[4096]; /* This is cheating */ -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int serial_paranoia_check(struct sun_serial *info, dev_t device, const char *routine) @@ -1628,7 +1628,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sun_serial *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; unsigned char r0; @@ -1844,7 +1844,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.41 $"; + char *revision = "$Revision: 1.42 $"; char *version, *p; version = strchr(revision, ' '); @@ -2517,8 +2517,8 @@ info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); printk("tty%02d at 0x%04x (irq = %s)", info->line, info->port, __irq_itoa(info->irq)); printk(" is a Zilog8530\n"); diff -ur --new-file old/linux/drivers/sbus/char/zs.h new/linux/drivers/sbus/char/zs.h --- old/linux/drivers/sbus/char/zs.h Thu Sep 4 21:54:49 1997 +++ new/linux/drivers/sbus/char/zs.h Wed May 12 17:41:15 1999 @@ -1,4 +1,4 @@ -/* $Id: zs.h,v 1.1 1997/08/28 02:23:45 ecd Exp $ +/* $Id: zs.h,v 1.2 1999/05/12 11:15:31 davem Exp $ * zs.h: Definitions for the Sparc Zilog serial driver. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -151,8 +151,8 @@ struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; }; diff -ur --new-file old/linux/drivers/scsi/atari_scsi.c new/linux/drivers/scsi/atari_scsi.c --- old/linux/drivers/scsi/atari_scsi.c Thu Jul 30 20:17:10 1998 +++ new/linux/drivers/scsi/atari_scsi.c Wed May 12 00:49:26 1999 @@ -497,9 +497,9 @@ static int falcon_got_lock = 0; -static struct wait_queue *falcon_fairness_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait); static int falcon_trying_lock = 0; -static struct wait_queue *falcon_try_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait); static int falcon_dont_release = 0; /* This function releases the lock on the DMA chip if there is no diff -ur --new-file old/linux/drivers/scsi/eata_dma_proc.c new/linux/drivers/scsi/eata_dma_proc.c --- old/linux/drivers/scsi/eata_dma_proc.c Thu Jan 7 18:28:47 1999 +++ new/linux/drivers/scsi/eata_dma_proc.c Wed May 12 22:27:37 1999 @@ -184,7 +184,7 @@ * Do the command and wait for it to finish. */ { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); scmd.request.rq_status = RQ_SCSI_BUSY; scmd.request.sem = &sem; scsi_do_cmd (&scmd, cmnd, buff + 0x144, 0x66, @@ -314,7 +314,7 @@ * Do the command and wait for it to finish. */ { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); scmd.request.rq_status = RQ_SCSI_BUSY; scmd.request.sem = &sem; scsi_do_cmd (&scmd, cmnd, buff2, 0x144, diff -ur --new-file old/linux/drivers/scsi/gdth_proc.c new/linux/drivers/scsi/gdth_proc.c --- old/linux/drivers/scsi/gdth_proc.c Mon Apr 12 18:56:16 1999 +++ new/linux/drivers/scsi/gdth_proc.c Wed May 12 22:27:37 1999 @@ -931,7 +931,7 @@ static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout) { char cmnd[12]; - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); TRACE2(("gdth_do_cmd()\n")); memset(cmnd, 0, 12); diff -ur --new-file old/linux/drivers/scsi/hosts.c new/linux/drivers/scsi/hosts.c --- old/linux/drivers/scsi/hosts.c Mon Apr 12 18:51:04 1999 +++ new/linux/drivers/scsi/hosts.c Tue May 11 23:37:40 1999 @@ -665,7 +665,7 @@ retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */ next_scsi_host++; retval->host_queue = NULL; - retval->host_wait = NULL; + init_waitqueue_head(&retval->host_wait); retval->resetting = 0; retval->last_reset = 0; retval->irq = 0; @@ -738,7 +738,7 @@ */ static void launch_error_handler_thread(struct Scsi_Host * shpnt) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); shpnt->eh_notify = &sem; diff -ur --new-file old/linux/drivers/scsi/hosts.h new/linux/drivers/scsi/hosts.h --- old/linux/drivers/scsi/hosts.h Tue May 11 19:36:25 1999 +++ new/linux/drivers/scsi/hosts.h Sun May 16 22:19:07 1999 @@ -313,7 +313,7 @@ host. */ unsigned int eh_active:1; /* Indicates the eh thread is awake and active if this is true. */ - struct wait_queue * host_wait; + wait_queue_head_t host_wait; Scsi_Host_Template * hostt; atomic_t host_active; /* commands checked out */ volatile unsigned short host_busy; /* commands actually active on low-level */ diff -ur --new-file old/linux/drivers/scsi/ide-scsi.c new/linux/drivers/scsi/ide-scsi.c --- old/linux/drivers/scsi/ide-scsi.c Fri Apr 23 04:24:50 1999 +++ new/linux/drivers/scsi/ide-scsi.c Fri May 14 08:23:27 1999 @@ -40,12 +40,11 @@ #include #include #include +#include #include #include #include - -#include "../block/ide.h" #include "scsi.h" #include "hosts.h" diff -ur --new-file old/linux/drivers/scsi/megaraid.c new/linux/drivers/scsi/megaraid.c --- old/linux/drivers/scsi/megaraid.c Fri May 7 08:14:37 1999 +++ new/linux/drivers/scsi/megaraid.c Wed May 12 00:48:45 1999 @@ -1522,7 +1522,7 @@ *----------------------------------------------------------------------*/ volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; -static struct wait_queue *internal_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(internal_wait); static void internal_done (Scsi_Cmnd * SCpnt) { diff -ur --new-file old/linux/drivers/scsi/pluto.c new/linux/drivers/scsi/pluto.c --- old/linux/drivers/scsi/pluto.c Tue Mar 16 01:11:31 1999 +++ new/linux/drivers/scsi/pluto.c Wed May 12 17:41:15 1999 @@ -54,7 +54,7 @@ static int fcscount __initdata = 0; static atomic_t fcss __initdata = ATOMIC_INIT(0); static struct timer_list fc_timer __initdata = { 0 }; -struct semaphore fc_sem __initdata = MUTEX_LOCKED; +DECLARE_MUTEX_LOCKED(fc_sem); static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); diff -ur --new-file old/linux/drivers/scsi/scsi.c new/linux/drivers/scsi/scsi.c --- old/linux/drivers/scsi/scsi.c Thu Apr 29 20:53:41 1999 +++ new/linux/drivers/scsi/scsi.c Tue May 11 23:37:40 1999 @@ -473,6 +473,8 @@ SDpnt->host = shpnt; SDpnt->online = TRUE; + init_waitqueue_head(&SDpnt->device_wait); + /* * Next, hook the device to the host in question. */ @@ -660,7 +662,7 @@ SCpnt->lun = SDpnt->lun; SCpnt->channel = SDpnt->channel; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.sem = &sem; SCpnt->request.rq_status = RQ_SCSI_BUSY; spin_lock_irq(&io_request_lock); @@ -703,7 +705,7 @@ scsi_cmd[5] = 0; SCpnt->cmd_len = 0; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.sem = &sem; SCpnt->request.rq_status = RQ_SCSI_BUSY; spin_lock_irq(&io_request_lock); @@ -849,7 +851,7 @@ scsi_cmd[5] = 0; SCpnt->cmd_len = 0; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.sem = &sem; spin_lock_irq(&io_request_lock); @@ -890,6 +892,8 @@ SDpnt->device_queue = SCpnt; SDpnt->online = TRUE; + init_waitqueue_head(&SDpnt->device_wait); + /* * Since we just found one device, there had damn well better be one in the list * already. @@ -2639,7 +2643,7 @@ { if( shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code ) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); shpnt->eh_notify = &sem; kernel_thread((int (*)(void *))scsi_error_handler, @@ -2876,7 +2880,7 @@ && shpnt->hostt->use_new_eh_code && shpnt->ehandler != NULL ) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); shpnt->eh_notify = &sem; send_sig(SIGKILL, shpnt->ehandler, 1); diff -ur --new-file old/linux/drivers/scsi/scsi.h new/linux/drivers/scsi/scsi.h --- old/linux/drivers/scsi/scsi.h Tue May 11 19:36:28 1999 +++ new/linux/drivers/scsi/scsi.h Sun May 16 22:19:09 1999 @@ -417,7 +417,7 @@ */ struct scsi_device * next; /* Used for linked list */ struct scsi_device * prev; /* Used for linked list */ - struct wait_queue * device_wait;/* Used to wait if + wait_queue_head_t device_wait;/* Used to wait if device is busy */ struct Scsi_Host * host; volatile unsigned short device_busy; /* commands actually active on low-level */ @@ -711,7 +711,7 @@ #define SCSI_SLEEP(QUEUE, CONDITION) { \ if (CONDITION) { \ - struct wait_queue wait = { current, NULL}; \ + DECLARE_WAITQUEUE(wait, current); \ add_wait_queue(QUEUE, &wait); \ for(;;) { \ current->state = TASK_UNINTERRUPTIBLE; \ diff -ur --new-file old/linux/drivers/scsi/scsi_error.c new/linux/drivers/scsi/scsi_error.c --- old/linux/drivers/scsi/scsi_error.c Thu Feb 25 01:27:54 1999 +++ new/linux/drivers/scsi/scsi_error.c Tue May 11 23:37:40 1999 @@ -560,7 +560,7 @@ void scsi_sleep (int timeout) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); struct timer_list timer; init_timer(&timer); @@ -603,7 +603,7 @@ if (host->can_queue) { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->eh_state = SCSI_STATE_QUEUED; @@ -1924,7 +1924,7 @@ { struct Scsi_Host * host = (struct Scsi_Host *) data; int rtn; - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); unsigned long flags; lock_kernel(); diff -ur --new-file old/linux/drivers/scsi/scsi_ioctl.c new/linux/drivers/scsi/scsi_ioctl.c --- old/linux/drivers/scsi/scsi_ioctl.c Thu Apr 29 20:53:41 1999 +++ new/linux/drivers/scsi/scsi_ioctl.c Tue May 11 23:37:40 1999 @@ -113,7 +113,7 @@ SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); SCpnt = scsi_allocate_device(NULL, dev, 1); { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.sem = &sem; scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries); spin_unlock_irqrestore(&io_request_lock, flags); @@ -289,7 +289,7 @@ SCpnt = scsi_allocate_device(NULL, dev, 1); { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.sem = &sem; scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, timeout, retries); diff -ur --new-file old/linux/drivers/scsi/sd.c new/linux/drivers/scsi/sd.c --- old/linux/drivers/scsi/sd.c Thu Apr 29 20:53:41 1999 +++ new/linux/drivers/scsi/sd.c Tue May 11 23:37:40 1999 @@ -1183,7 +1183,7 @@ SCpnt->sense_buffer[2] = 0; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); /* Mark as really busy again */ SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.sem = &sem; @@ -1221,7 +1221,7 @@ SCpnt->sense_buffer[2] = 0; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); /* Mark as really busy again */ SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.sem = &sem; @@ -1263,7 +1263,7 @@ SCpnt->sense_buffer[2] = 0; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); /* Mark as really busy again */ SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.sem = &sem; @@ -1444,7 +1444,7 @@ /* same code as READCAPA !! */ { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy again */ SCpnt->request.sem = &sem; scsi_do_cmd (SCpnt, diff -ur --new-file old/linux/drivers/scsi/sd_ioctl.c new/linux/drivers/scsi/sd_ioctl.c --- old/linux/drivers/scsi/sd_ioctl.c Thu Feb 25 01:27:54 1999 +++ new/linux/drivers/scsi/sd_ioctl.c Sun May 16 08:43:04 1999 @@ -15,6 +15,7 @@ #define MAJOR_NR SCSI_DISK0_MAJOR #include +#include #include "scsi.h" #include #include "hosts.h" @@ -79,41 +80,19 @@ (long *) arg); return 0; + case BLKROSET: + case BLKROGET: case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) - return -EINVAL; - error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if (error) - return error; - put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - return 0; - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; - + case BLKSSZGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_scsidisk(dev, 1); - - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[MAJOR(dev)][MINOR(dev)&0x0F], - (int *)arg); - - RO_IOCTLS(dev, arg); default: return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); diff -ur --new-file old/linux/drivers/scsi/sg.c new/linux/drivers/scsi/sg.c --- old/linux/drivers/scsi/sg.c Fri May 7 20:05:30 1999 +++ new/linux/drivers/scsi/sg.c Sat May 15 02:56:58 1999 @@ -135,7 +135,7 @@ { struct sg_fd * nextfp; /* NULL when last opened fd on this device */ struct sg_device * parentdp; /* owning device */ - struct wait_queue * read_wait; /* queue read until command done */ + wait_queue_head_t read_wait; /* queue read until command done */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ char * fst_buf; /* try to grab SG_SCATTER_SZ sized buffer on open */ int fb_size; /* actual size of allocated fst_buf */ @@ -153,7 +153,7 @@ typedef struct sg_device /* holds the state of each scsi generic device */ { Scsi_Device * device; - struct wait_queue * generic_wait;/* queue open if O_EXCL on prev. open */ + wait_queue_head_t generic_wait;/* queue open if O_EXCL on prev. open */ int sg_tablesize; /* adapter's max scatter-gather table size */ Sg_fd * headfp; /* first open fd belonging to this device */ kdev_t i_rdev; /* holds device major+minor number */ @@ -988,7 +988,7 @@ SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); sdp->device = scsidp; - sdp->generic_wait = NULL; + init_waitqueue_head(&sdp->generic_wait); sdp->headfp= NULL; sdp->exclude = 0; sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */ @@ -1334,13 +1334,13 @@ return sdp->headfp; } sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); - if (sfp) { - memset(sfp, 0, sizeof(Sg_fd)); - sfp->my_mem_src = SG_HEAP_KMAL; - } - else - return NULL; - + if (!sfp) + return NULL; + + memset(sfp, 0, sizeof(Sg_fd)); + sfp->my_mem_src = SG_HEAP_KMAL; + + init_waitqueue_head(&sfp->read_wait); sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->force_packid = SG_DEF_FORCE_PACK_ID; sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? diff -ur --new-file old/linux/drivers/scsi/sr.c new/linux/drivers/scsi/sr.c --- old/linux/drivers/scsi/sr.c Fri Jan 15 23:41:04 1999 +++ new/linux/drivers/scsi/sr.c Tue May 11 23:37:40 1999 @@ -895,7 +895,7 @@ /* Do the command and wait.. */ { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.sem = &sem; spin_lock_irqsave(&io_request_lock, flags); scsi_do_cmd (SCpnt, diff -ur --new-file old/linux/drivers/scsi/sr_ioctl.c new/linux/drivers/scsi/sr_ioctl.c --- old/linux/drivers/scsi/sr_ioctl.c Mon May 10 22:01:21 1999 +++ new/linux/drivers/scsi/sr_ioctl.c Sun May 16 08:43:04 1999 @@ -7,6 +7,7 @@ #include #include +#include #include "scsi.h" #include "hosts.h" #include @@ -64,7 +65,7 @@ if( !scsi_block_when_processing_errors(SDev) ) return -ENODEV; { - struct semaphore sem = MUTEX_LOCKED; + DECLARE_MUTEX_LOCKED(sem); SCpnt->request.sem = &sem; spin_lock_irqsave(&io_request_lock, flags); scsi_do_cmd(SCpnt, @@ -122,11 +123,9 @@ if (!quiet) printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL " "REQUEST.\n", target); - if ((SCpnt->sense_buffer[12] == 0x20 || - SCpnt->sense_buffer[12] == 0x24) && + if (SCpnt->sense_buffer[12] == 0x20 && SCpnt->sense_buffer[13] == 0x00) { /* sense: Invalid command operation code */ - /* or Invalid field in cdb */ err = -EDRIVE_CANT_DO_THIS; } else { err = -EINVAL; @@ -770,7 +769,7 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) { - int target, err; + int target; target = MINOR(cdi->dev); @@ -857,40 +856,14 @@ spin_unlock_irqrestore(&io_request_lock, flags); return rc; } - case BLKRAGET: - if (!arg) - return -EINVAL; - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if (err) - return err; - put_user(read_ahead[MAJOR(cdi->dev)], (long *) arg); - return 0; + case BLKROSET: + case BLKROGET: case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(cdi->dev)) - return -EINVAL; - if(arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(cdi->dev)] = arg; - return 0; - - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[MAJOR(cdi->dev)][MINOR(cdi->dev)], - (int *)arg); - - RO_IOCTLS(cdi->dev,arg); - + case BLKRAGET: case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(cdi->dev)) - return -EINVAL; - fsync_dev(cdi->dev); - invalidate_buffers(cdi->dev); - return 0; + case BLKSSZGET: + return blk_ioctl(cdi->dev, cmd, arg); default: return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); diff -ur --new-file old/linux/drivers/scsi/st.c new/linux/drivers/scsi/st.c --- old/linux/drivers/scsi/st.c Mon Mar 8 00:20:26 1999 +++ new/linux/drivers/scsi/st.c Tue May 11 23:37:40 1999 @@ -279,7 +279,7 @@ } cmd[1] |= (SCpnt->lun << 5) & 0xe0; - STp->sem = MUTEX_LOCKED; + init_MUTEX_LOCKED(&STp->sem); SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; if (SCpnt->use_sg) { diff -ur --new-file old/linux/drivers/scsi/st.h new/linux/drivers/scsi/st.h --- old/linux/drivers/scsi/st.h Sun Sep 6 18:48:30 1998 +++ new/linux/drivers/scsi/st.h Sun May 16 00:05:36 1999 @@ -65,7 +65,7 @@ typedef struct { kdev_t devt; unsigned capacity; - struct wait_queue * waiting; + wait_queue_head_t waiting; Scsi_Device* device; struct semaphore sem; ST_buffer * buffer; diff -ur --new-file old/linux/drivers/sgi/char/sgiserial.c new/linux/drivers/sgi/char/sgiserial.c --- old/linux/drivers/sgi/char/sgiserial.c Thu Nov 5 18:58:44 1998 +++ new/linux/drivers/sgi/char/sgiserial.c Sun May 16 00:05:36 1999 @@ -33,7 +33,7 @@ #define NUM_SERIAL 1 /* One chip on board. */ #define NUM_CHANNELS (NUM_SERIAL * 2) -extern struct wait_queue * keypress_wait; +extern struct wait_queue_head_t keypress_wait; struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, }; struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, }; @@ -1519,7 +1519,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sgi_serial *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; diff -ur --new-file old/linux/drivers/sgi/char/sgiserial.h new/linux/drivers/sgi/char/sgiserial.h --- old/linux/drivers/sgi/char/sgiserial.h Wed Dec 10 19:31:11 1997 +++ new/linux/drivers/sgi/char/sgiserial.h Sun May 16 00:05:36 1999 @@ -158,8 +158,8 @@ struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; }; diff -ur --new-file old/linux/drivers/sgi/char/shmiq.c new/linux/drivers/sgi/char/shmiq.c --- old/linux/drivers/sgi/char/shmiq.c Mon Aug 24 22:14:10 1998 +++ new/linux/drivers/sgi/char/shmiq.c Sun May 16 00:05:36 1999 @@ -82,7 +82,7 @@ int events; int mapped; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; struct fasync_struct *fasync; } shmiqs [MAX_SHMI_QUEUES]; diff -ur --new-file old/linux/drivers/sgi/char/usema.c new/linux/drivers/sgi/char/usema.c --- old/linux/drivers/sgi/char/usema.c Mon Aug 24 22:02:44 1998 +++ new/linux/drivers/sgi/char/usema.c Sun May 16 00:05:36 1999 @@ -39,7 +39,7 @@ struct irix_usema { struct file *filp; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; }; static int diff -ur --new-file old/linux/drivers/sound/dev_table.c new/linux/drivers/sound/dev_table.c --- old/linux/drivers/sound/dev_table.c Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/sound/dev_table.c Wed May 12 08:40:50 1999 @@ -435,9 +435,9 @@ return -(ENOMEM); } memset((char *) op, 0, sizeof(struct audio_operations)); - init_waitqueue(&op->in_sleeper); - init_waitqueue(&op->out_sleeper); - init_waitqueue(&op->poll_sleeper); + init_waitqueue_head(&op->in_sleeper); + init_waitqueue_head(&op->out_sleeper); + init_waitqueue_head(&op->poll_sleeper); if (driver_size < sizeof(struct audio_driver)) memset((char *) d, 0, sizeof(struct audio_driver)); diff -ur --new-file old/linux/drivers/sound/dev_table.h new/linux/drivers/sound/dev_table.h --- old/linux/drivers/sound/dev_table.h Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/sound/dev_table.h Fri May 14 08:22:48 1999 @@ -234,9 +234,9 @@ int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ /* fields formerly in dmabuf.c */ - struct wait_queue *in_sleeper; - struct wait_queue *out_sleeper; - struct wait_queue *poll_sleeper; + wait_queue_head_t in_sleeper; + wait_queue_head_t out_sleeper; + wait_queue_head_t poll_sleeper; /* fields formerly in audio.c */ int audio_mode; diff -ur --new-file old/linux/drivers/sound/dmasound.c new/linux/drivers/sound/dmasound.c --- old/linux/drivers/sound/dmasound.c Thu Mar 11 06:48:46 1999 +++ new/linux/drivers/sound/dmasound.c Wed May 12 08:28:01 1999 @@ -809,7 +809,7 @@ * Bit 1 is set: a frame is playing */ int playing; - struct wait_queue *write_queue, *open_queue, *sync_queue; + wait_queue_head_t write_queue, open_queue, sync_queue; int open_mode; int busy, syncing; #ifdef CONFIG_ATARI @@ -4623,7 +4623,9 @@ if (sq_unit < 0) return; - sq.write_queue = sq.open_queue = sq.sync_queue = 0; + init_waitqueue_head(&sq.write_queue); + init_waitqueue_head(&sq.open_queue); + init_waitqueue_head(&sq.sync_queue); sq.busy = 0; /* whatever you like as startup mode for /dev/dsp, diff -ur --new-file old/linux/drivers/sound/es1370.c new/linux/drivers/sound/es1370.c --- old/linux/drivers/sound/es1370.c Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/sound/es1370.c Wed May 12 22:27:37 1999 @@ -310,7 +310,7 @@ spinlock_t lock; struct semaphore open_sem; mode_t open_mode; - struct wait_queue *open_wait; + wait_queue_head_t open_wait; struct dmabuf { void *rawbuf; @@ -321,7 +321,7 @@ unsigned total_bytes; int count; unsigned error; /* over/underrun */ - struct wait_queue *wait; + wait_queue_head_t wait; /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; @@ -339,8 +339,8 @@ struct { unsigned ird, iwr, icnt; unsigned ord, owr, ocnt; - struct wait_queue *iwait; - struct wait_queue *owait; + wait_queue_head_t iwait; + wait_queue_head_t owait; unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; @@ -1007,7 +1007,7 @@ static int drain_dac1(struct es1370_state *s, int nonblock) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; @@ -1042,7 +1042,7 @@ static int drain_dac2(struct es1370_state *s, int nonblock) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; @@ -2191,7 +2191,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file) { struct es1370_state *s = (struct es1370_state *)file->private_data; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; unsigned count, tmo; @@ -2308,13 +2308,13 @@ continue; } memset(s, 0, sizeof(struct es1370_state)); - init_waitqueue(&s->dma_adc.wait); - init_waitqueue(&s->dma_dac1.wait); - init_waitqueue(&s->dma_dac2.wait); - init_waitqueue(&s->open_wait); - init_waitqueue(&s->midi.iwait); - init_waitqueue(&s->midi.owait); - s->open_sem = MUTEX; + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac1.wait); + init_waitqueue_head(&s->dma_dac2.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); s->magic = ES1370_MAGIC; s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->irq = pcidev->irq; diff -ur --new-file old/linux/drivers/sound/es1371.c new/linux/drivers/sound/es1371.c --- old/linux/drivers/sound/es1371.c Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/sound/es1371.c Wed May 12 22:27:37 1999 @@ -361,7 +361,7 @@ spinlock_t lock; struct semaphore open_sem; mode_t open_mode; - struct wait_queue *open_wait; + wait_queue_head_t open_wait; struct dmabuf { void *rawbuf; @@ -372,7 +372,7 @@ unsigned total_bytes; int count; unsigned error; /* over/underrun */ - struct wait_queue *wait; + wait_queue_head_t wait; /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; @@ -390,8 +390,8 @@ struct { unsigned ird, iwr, icnt; unsigned ord, owr, ocnt; - struct wait_queue *iwait; - struct wait_queue *owait; + wait_queue_head_t iwait; + wait_queue_head_t owait; unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; @@ -1454,7 +1454,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; @@ -1489,7 +1489,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; @@ -2625,7 +2625,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file) { struct es1371_state *s = (struct es1371_state *)file->private_data; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; unsigned count, tmo; @@ -2745,13 +2745,13 @@ continue; } memset(s, 0, sizeof(struct es1371_state)); - init_waitqueue(&s->dma_adc.wait); - init_waitqueue(&s->dma_dac1.wait); - init_waitqueue(&s->dma_dac2.wait); - init_waitqueue(&s->open_wait); - init_waitqueue(&s->midi.iwait); - init_waitqueue(&s->midi.owait); - s->open_sem = MUTEX; + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac1.wait); + init_waitqueue_head(&s->dma_dac2.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); s->magic = ES1371_MAGIC; s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->irq = pcidev->irq; diff -ur --new-file old/linux/drivers/sound/gus_wave.c new/linux/drivers/sound/gus_wave.c --- old/linux/drivers/sound/gus_wave.c Thu Jan 28 20:25:04 1999 +++ new/linux/drivers/sound/gus_wave.c Wed May 12 08:40:50 1999 @@ -118,7 +118,7 @@ static int gus_audio_bsize; static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ -static struct wait_queue *dram_sleeper = NULL; +static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper); /* * Variables and buffers for PCM output @@ -1663,7 +1663,7 @@ gus_no_dma = 0; } - init_waitqueue(&dram_sleeper); + init_waitqueue_head(&dram_sleeper); gus_busy = 1; active_device = GUS_DEV_WAVE; diff -ur --new-file old/linux/drivers/sound/lowlevel/awe_compat.h new/linux/drivers/sound/lowlevel/awe_compat.h --- old/linux/drivers/sound/lowlevel/awe_compat.h Mon Mar 8 00:22:06 1999 +++ new/linux/drivers/sound/lowlevel/awe_compat.h Sun May 16 00:05:36 1999 @@ -245,7 +245,7 @@ #endif /* AWE_MODULE_SUPPORT */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -inline static void interruptible_sleep_on_timeout(struct wait_queue **q, unsigned long timeout) +inline static void interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout) { current->timeout = jiffies + timeout; interruptible_sleep_on(q); diff -ur --new-file old/linux/drivers/sound/lowlevel/awe_wave.c new/linux/drivers/sound/lowlevel/awe_wave.c --- old/linux/drivers/sound/lowlevel/awe_wave.c Mon Mar 8 00:22:06 1999 +++ new/linux/drivers/sound/lowlevel/awe_wave.c Sun May 16 00:05:36 1999 @@ -979,7 +979,7 @@ } #else -static struct wait_queue *awe_sleeper = NULL; +static DECLARE_WAIT_QUEUE_HEAD(awe_sleeper); static void awe_wait(unsigned short delay) { interruptible_sleep_on_timeout(&awe_sleeper, (HZ * (unsigned long)delay + 44099) / 44100); diff -ur --new-file old/linux/drivers/sound/midibuf.c new/linux/drivers/sound/midibuf.c --- old/linux/drivers/sound/midibuf.c Wed Dec 16 21:52:01 1998 +++ new/linux/drivers/sound/midibuf.c Wed May 12 08:40:50 1999 @@ -29,8 +29,8 @@ #define MAX_QUEUE_SIZE 4000 -static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] = {NULL}; -static struct wait_queue *input_sleeper[MAX_MIDI_DEV] = {NULL}; +static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV]; +static wait_queue_head_t input_sleeper[MAX_MIDI_DEV]; struct midi_buf { @@ -202,8 +202,8 @@ midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; open_devs++; - init_waitqueue(&midi_sleeper[dev]); - init_waitqueue(&input_sleeper[dev]); + init_waitqueue_head(&midi_sleeper[dev]); + init_waitqueue_head(&input_sleeper[dev]); if (open_devs < 2) /* This was first open */ { diff -ur --new-file old/linux/drivers/sound/msnd.h new/linux/drivers/sound/msnd.h --- old/linux/drivers/sound/msnd.h Wed Dec 16 21:52:01 1998 +++ new/linux/drivers/sound/msnd.h Sun May 16 00:05:37 1999 @@ -231,8 +231,9 @@ #define F_EXT_MIDI_INUSE 9 #define F_INT_MIDI_INUSE 10 #define F_DISABLE_WRITE_NDELAY 11 - struct wait_queue *writeblock, *readblock; - struct wait_queue *writeflush; + wait_queue_head_t writeblock; + wait_queue_head_t readblock; + wait_queue_head_t writeflush; #ifndef LINUX20 spinlock_t lock; #endif diff -ur --new-file old/linux/drivers/sound/msnd_pinnacle.c new/linux/drivers/sound/msnd_pinnacle.c --- old/linux/drivers/sound/msnd_pinnacle.c Mon Jan 4 20:37:30 1999 +++ new/linux/drivers/sound/msnd_pinnacle.c Wed May 12 08:40:50 1999 @@ -1913,9 +1913,9 @@ if (digital) set_bit(F_HAVEDIGITAL, &dev.flags); #endif - init_waitqueue(&dev.writeblock); - init_waitqueue(&dev.readblock); - init_waitqueue(&dev.writeflush); + init_waitqueue_head(&dev.writeblock); + init_waitqueue_head(&dev.readblock); + init_waitqueue_head(&dev.writeflush); msnd_fifo_init(&dev.DAPF); msnd_fifo_init(&dev.DARF); #ifndef LINUX20 diff -ur --new-file old/linux/drivers/sound/sequencer.c new/linux/drivers/sound/sequencer.c --- old/linux/drivers/sound/sequencer.c Mon Mar 8 00:22:06 1999 +++ new/linux/drivers/sound/sequencer.c Wed May 12 08:40:50 1999 @@ -53,8 +53,8 @@ #define SEQ_2 2 static int seq_mode = SEQ_1; -static struct wait_queue *seq_sleeper = NULL; -static struct wait_queue *midi_sleeper = NULL; +static DECLARE_WAIT_QUEUE_HEAD(seq_sleeper); +static DECLARE_WAIT_QUEUE_HEAD(midi_sleeper); static int midi_opened[MAX_MIDI_DEV] = { 0 @@ -1117,8 +1117,8 @@ if (seq_mode == SEQ_2) tmr->open(tmr_no, seq_mode); - init_waitqueue(&seq_sleeper); - init_waitqueue(&midi_sleeper); + init_waitqueue_head(&seq_sleeper); + init_waitqueue_head(&midi_sleeper); output_threshold = SEQ_MAX_QUEUE / 2; return 0; diff -ur --new-file old/linux/drivers/sound/sonicvibes.c new/linux/drivers/sound/sonicvibes.c --- old/linux/drivers/sound/sonicvibes.c Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/sound/sonicvibes.c Wed May 12 22:27:37 1999 @@ -286,7 +286,7 @@ spinlock_t lock; struct semaphore open_sem; mode_t open_mode; - struct wait_queue *open_wait; + wait_queue_head_t open_wait; struct dmabuf { void *rawbuf; @@ -297,7 +297,7 @@ unsigned total_bytes; int count; unsigned error; /* over/underrun */ - struct wait_queue *wait; + wait_queue_head_t wait; /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; @@ -315,8 +315,8 @@ struct { unsigned ird, iwr, icnt; unsigned ord, owr, ocnt; - struct wait_queue *iwait; - struct wait_queue *owait; + wait_queue_head_t iwait; + wait_queue_head_t owait; struct timer_list timer; unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; @@ -1241,7 +1241,7 @@ static int drain_dac(struct sv_state *s, int nonblock) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; @@ -2043,7 +2043,7 @@ static int sv_midi_release(struct inode *inode, struct file *file) { struct sv_state *s = (struct sv_state *)file->private_data; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; unsigned count, tmo; @@ -2344,12 +2344,12 @@ continue; } memset(s, 0, sizeof(struct sv_state)); - init_waitqueue(&s->dma_adc.wait); - init_waitqueue(&s->dma_dac.wait); - init_waitqueue(&s->open_wait); - init_waitqueue(&s->midi.iwait); - init_waitqueue(&s->midi.owait); - s->open_sem = MUTEX; + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); s->magic = SV_MAGIC; s->iosb = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->ioenh = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; diff -ur --new-file old/linux/drivers/sound/wavfront.c new/linux/drivers/sound/wavfront.c --- old/linux/drivers/sound/wavfront.c Fri Jan 15 07:59:47 1999 +++ new/linux/drivers/sound/wavfront.c Wed May 12 08:40:50 1999 @@ -290,7 +290,7 @@ int samples_used; /* how many */ char interrupts_on; /* h/w MPU interrupts enabled ? */ char rom_samples_rdonly; /* can we write on ROM samples */ - struct wait_queue *interrupt_sleeper; + wait_queue_head_t interrupt_sleeper; } dev; static int detect_wffx(void); @@ -2535,7 +2535,7 @@ } - init_waitqueue (&dev.interrupt_sleeper); + init_waitqueue_head (&dev.interrupt_sleeper); if (wavefront_hw_reset ()) { printk (KERN_WARNING LOGNAME "hardware reset failed\n"); diff -ur --new-file old/linux/drivers/usb/Config.in new/linux/drivers/usb/Config.in --- old/linux/drivers/usb/Config.in Mon May 10 19:18:34 1999 +++ new/linux/drivers/usb/Config.in Mon May 17 07:23:31 1999 @@ -11,20 +11,24 @@ mainmenu_option next_comment comment 'USB drivers - not for the faint of heart' -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB - if [ ! "$CONFIG_USB" = "n" ]; then - bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI - bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI - bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD - if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then - bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB - fi +tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB +if [ ! "$CONFIG_USB" = "n" ]; then + bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI - bool 'USB mouse support' CONFIG_USB_MOUSE - bool 'USB keyboard support' CONFIG_USB_KBD - bool 'USB audio parsing support' CONFIG_USB_AUDIO + bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI + if [ "$CONFIG_USB_OHCI" = "y" ]; then + bool ' Enable tons of OHCI debugging output?' CONFIG_USB_OHCI_DEBUG fi + + bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD + if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then + bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB + fi + + bool 'USB mouse support' CONFIG_USB_MOUSE + bool 'USB keyboard support' CONFIG_USB_KBD + bool 'USB audio parsing support' CONFIG_USB_AUDIO + bool 'USB Abstract Control Model support' CONFIG_USB_ACM fi endmenu diff -ur --new-file old/linux/drivers/usb/Makefile new/linux/drivers/usb/Makefile --- old/linux/drivers/usb/Makefile Mon May 10 19:18:34 1999 +++ new/linux/drivers/usb/Makefile Sat May 15 03:09:57 1999 @@ -24,12 +24,20 @@ USBX_OBJS += mouse.o endif +ifeq ($(CONFIG_USB_ACM),y) + USBX_OBJS += acm.o +endif + ifeq ($(CONFIG_USB_KBD),y) USBX_OBJS += keyboard.o keymap.o endif ifeq ($(CONFIG_USB_AUDIO),y) USBX_OBJS += audio.o +endif + +ifeq ($(CONFIG_USB_CPIA),y) + USBX_OBJS += cpia.o endif ifeq ($(CONFIG_USB), y) diff -ur --new-file old/linux/drivers/usb/README.ohci new/linux/drivers/usb/README.ohci --- old/linux/drivers/usb/README.ohci Tue May 11 19:04:03 1999 +++ new/linux/drivers/usb/README.ohci Mon May 17 07:23:31 1999 @@ -1,3 +1,31 @@ +May 16, 1999 16:20:54 + +EDs are now allocated dynamically from their device's pool. Root hub +status changes should stop the infinite "no device connected" messages +that occurred after removing a device. + +TODO: + +~ Add the concept of a td_group to lump TDs associated with a single + data transfer request from the higher layers. This will be needed + for bulk and all larger transfers that will span multiple TDs but + which need to allocate/free them as a group as things happen. I + am thinking about create_td_group and free_td_group functions... +~ Add bulk transfer support. +~ Add Isochronous transfer support. These have their own special + format TDs to allow for several DMA data pointers. Kinda neat, but + likely harder to use through a generic interface in practice. +~ Support dynamic allocation & growth of the TD/ED pools. Merge them + into global pools rather than a today's static per device allocation. + +KNOWN BUGS: + +~ Unplugging a hub causes khubd to Oops. I don't think this is + directly related to OHCI, but due to the fact that the interrupt TD + for the hub is never stopped. We need a usb_release_irq() that gets + called using the "IRQ handle" that should be returned by + usb_request_irq(). + May 09, 1999 16:25:58 Cool, things are working "well" now. (I'm not getting oops's from the diff -ur --new-file old/linux/drivers/usb/acm.c new/linux/drivers/usb/acm.c --- old/linux/drivers/usb/acm.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/acm.c Sat May 15 03:09:57 1999 @@ -0,0 +1,220 @@ +/* + * USB Abstract Control Model based on Brad Keryan's USB busmouse driver + * + * Armin Fuerst 5/8/1999 + * + * version 0.0: Driver sets up configuration, setus up data pipes, opens misc + * device. No actual data transfer is done, since we don't have bulk transfer, + * yet. Purely skeleton for now. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb.h" + +#define USB_ACM_MINOR 32 + +struct acm_state { + int present; /* this acm is plugged in */ + int active; /* someone is has this acm's device open */ + struct usb_device *dev; + unsigned int readpipe,writepipe; +}; + +static struct acm_state static_acm_state; + +spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED; + +static int acm_irq(int state, void *__buffer, void *dev_id) +{ +/* + signed char *data = __buffer; + struct acm_state *acm = &static_acm_state; + if(!acm->active) + return 1; +*/ + + /*We should so something useful here*/ + printk("ACM_USB_IRQ\n"); + + return 1; +} + +static int release_acm(struct inode * inode, struct file * file) +{ + struct acm_state *acm = &static_acm_state; + printk("ACM_FILE_RELEASE\n"); + +// fasync_acm(-1, file, 0); + if (--acm->active) + return 0; + return 0; +} + +static int open_acm(struct inode * inode, struct file * file) +{ + struct acm_state *acm = &static_acm_state; + printk("USB_FILE_OPEN\n"); + + if (!acm->present) + return -EINVAL; + if (acm->active++) + return 0; + return 0; +} + +static ssize_t write_acm(struct file * file, + const char * buffer, size_t count, loff_t *ppos) +{ + char * buffer="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + struct acm_state *acm = &static_acm_state; + printk("USB_FILE_WRITE\n"); + printk("writing:>%s<\n",buffer); + acm->dev->bus->op->bulk_msg(acm->dev,acm->writepipe,buffer, 26); + printk("done:>%s<\n",buffer); + printk("reading:>%s<\n",buffer); + acm->dev->bus->op->bulk_msg(acm->dev,acm->readpipe,buffer, 26); + printk("done:>%s<\n",buffer); + return -EINVAL; +} + +static ssize_t read_acm(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + printk("USB_FILE_READ\n"); + return -EINVAL; +} + +struct file_operations usb_acm_fops = { + NULL, /* acm_seek */ + read_acm, + write_acm, + NULL, /* acm_readdir */ + NULL, /* acm_poll */ + NULL, /* acm_ioctl */ + NULL, /* acm_mmap */ + open_acm, + NULL, /* flush */ + release_acm, + NULL, + NULL, /*fasync*/ +}; + +static struct miscdevice usb_acm = { + USB_ACM_MINOR, "USB ACM", &usb_acm_fops +}; + +static int acm_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct acm_state *acm = &static_acm_state; + int cfgnum; + + /* Only use CDC */ + if (dev->descriptor.bDeviceClass != 2 || + dev->descriptor.bDeviceSubClass != 0 || + dev->descriptor.bDeviceProtocol != 0) + return -1; + + /*Now scan all configs for a ACM configuration*/ + for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { + /* The first one should be Communications interface? */ + interface = &dev->config[cfgnum].interface[0]; + if (interface->bInterfaceClass != 2 || + interface->bInterfaceSubClass != 2 || + interface->bInterfaceProtocol != 1 || + interface->bNumEndpoints != 1) + continue; + + /*Which uses an interrupt input */ + endpoint = &interface->endpoint[0]; + if ((endpoint->bEndpointAddress & 0x80) != 0x80 || + (endpoint->bmAttributes & 3) != 3) + continue; + + /* The second one should be a Data interface? */ + interface = &dev->config[cfgnum].interface[1]; + if (interface->bInterfaceClass != 10 || + interface->bInterfaceSubClass != 0 || + interface->bInterfaceProtocol != 0 || + interface->bNumEndpoints != 2) + continue; + + /*With a bulk input */ + endpoint = &interface->endpoint[0]; + if ((endpoint->bEndpointAddress & 0x80) != 0x80 || + (endpoint->bmAttributes & 3) != 2) + continue; + + /*And a bulk output */ + endpoint = &interface->endpoint[1]; + if ((endpoint->bEndpointAddress & 0x80) == 0x80 || + (endpoint->bmAttributes & 3) != 2) + continue; + + printk("USB ACM found\n"); + usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue); + acm->dev=dev; + acm->readpipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[0]); + acm->writepipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[1]); + usb_request_irq(dev, usb_rcvctrlpipe(dev,&dev->config[cfgnum].interface[0].endpoint[0]), acm_irq, endpoint->bInterval, NULL); + acm->present = 1; + return 0; + } + + return -1; +} + +static void acm_disconnect(struct usb_device *dev) +{ + struct acm_state *acm = &static_acm_state; + + /* this might need work */ + acm->present = 0; +} + +static struct usb_driver acm_driver = { + "acm", + acm_probe, + acm_disconnect, + { NULL, NULL } +}; + +int usb_acm_init(void) +{ + struct acm_state *acm = &static_acm_state; + + misc_register(&usb_acm); + + acm->present = acm->active = 0; + + usb_register(&acm_driver); + printk(KERN_INFO "USB ACM registered.\n"); + return 0; +} + +#if 0 + +int init_module(void) +{ + return usb_acm_init(); +} + +void cleanup_module(void) +{ + /* this, too, probably needs work */ + usb_deregister(&acm_driver); + misc_deregister(&usb_acm); +} + +#endif diff -ur --new-file old/linux/drivers/usb/cpia.c new/linux/drivers/usb/cpia.c --- old/linux/drivers/usb/cpia.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/cpia.c Sat May 15 03:33:12 1999 @@ -0,0 +1,1255 @@ +/* + * USB CPiA Video Camera driver + * + * Supports CPiA based Video Camera's. Many manufacturers use this chipset. + * There's a good chance, if you have a USB video camera, it's a CPiA based + * one + * + * (C) Copyright 1999 Johannes Erdfelt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "usb.h" +#include "uhci.h" +#include "cpia.h" + +#define MAX_FRAME_SIZE (384 * 288 * 3) + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +/* convert virtual user memory address to physical address */ +/* (virt_to_phys only works for kmalloced kernel memory) */ + +static inline unsigned long uvirt_to_phys(unsigned long adr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + + pgd = pgd_offset(current->mm, adr); + if (pgd_none(*pgd)) + return 0; + pmd = pmd_offset(pgd, adr); + if (pmd_none(*pmd)) + return 0; + ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); + pte = *ptep; + if(pte_present(pte)) + return + virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); + return 0; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + return virt_to_bus(phys_to_virt(uvirt_to_phys(adr))); +} + +/* convert virtual kernel memory address to physical address */ +/* (virt_to_phys only works for kmalloced kernel memory) */ + +static inline unsigned long kvirt_to_phys(unsigned long adr) +{ + return uvirt_to_phys(VMALLOC_VMADDR(adr)); +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + return uvirt_to_bus(VMALLOC_VMADDR(adr)); +} + + +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr, page; + + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + mem=vmalloc(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_phys(adr); + mem_map_reserve(MAP_NR(phys_to_virt(page))); + adr+=PAGE_SIZE; + if (size > PAGE_SIZE) + size-=PAGE_SIZE; + else + size=0; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr, page; + + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_phys(adr); + mem_map_unreserve(MAP_NR(phys_to_virt(page))); + adr+=PAGE_SIZE; + if (size > PAGE_SIZE) + size-=PAGE_SIZE; + else + size=0; + } + vfree(mem); + } +} + +int usb_cpia_get_version(struct usb_device *dev, void *buf) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; + dr.request = USB_REQ_CPIA_GET_VERSION; + dr.value = 0; + dr.index = 0; + dr.length = 4; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 4); +} + +int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; + dr.request = USB_REQ_CPIA_GET_PNP_ID; + dr.value = 0; + dr.index = 0; + dr.length = 6; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 6); +} + +int usb_cpia_get_camera_status(struct usb_device *dev, void *buf) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; + dr.request = USB_REQ_CPIA_GET_CAMERA_STATUS; + dr.value = 0; + dr.index = 0; + dr.length = 8; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 8); +} + +int usb_cpia_goto_hi_power(struct usb_device *dev) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_GOTO_HI_POWER; + dr.value = 0; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_get_vp_version(struct usb_device *dev, void *buf) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_GET_VP_VERSION; + dr.value = 0; + dr.index = 0; + dr.length = 4; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buf, 4); +} + +int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_SET_SENSOR_FPS; + dr.value = (sensorclkdivisor << 8) + sensorbaserate; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_GRAB_FRAME; + dr.value = streamstartline << 8; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_upload_frame(struct usb_device *dev, int forceupload) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_UPLOAD_FRAME; + dr.value = forceupload; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_SET_GRAB_MODE; + dr.value = continuousgrab; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_SET_FORMAT; + dr.value = (subsample << 8) + size; + dr.index = order; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_SET_COMPRESSION; + dr.value = (decimation << 8) + compmode; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_INIT_STREAM_CAP; + dr.value = (streamstartline << 8) + skipframes; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_finistreamcap(struct usb_device *dev) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_FINI_STREAM_CAP; + dr.value = 0; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_startstreamcap(struct usb_device *dev) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_START_STREAM_CAP; + dr.value = 0; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_cpia_endstreamcap(struct usb_device *dev) +{ + devrequest dr; + + dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); + dr.request = USB_REQ_CPIA_END_STREAM_CAP; + dr.value = 0; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch)) + +static void cpia_parse_data(struct usb_cpia *cpia) +{ + unsigned char *data = cpia->scratch; + int done; + + done = 0; + while (!done && scratch_left(data)) { + switch (cpia->state) { + case STATE_SCANNING: + { + unsigned char *begin = data; + + /* We need atleast 2 bytes for the magic value */ + if (scratch_left(data) < 2) { + done = 1; + break; + } + + printk("header: %X\n", (*data << 8) + *(data + 1)); + if ((*data == 0x19) && (*(data + 1) == 0x68)) { + cpia->state = STATE_HEADER; + printk("moving to header\n"); + break; + } + + if (scratch_left(data) < 4) { + done = 1; + break; + } + + printk("Scanning for end of frame\n"); + while (scratch_left(data) >= 4) { + if ((*data == 0xFF) && + (*(data + 1) == 0xFF) && + (*(data + 2) == 0xFF) && + (*(data + 3) == 0xFF)) { + data += 4; + break; + } + data++; + } +printk("scan: scanned %d bytes\n", data-begin); + break; + } + case STATE_HEADER: + /* We need atleast 64 bytes for the header */ + if (scratch_left(data) < 64) { + done = 1; + break; + } + +printk("header: framerate %d\n", data[41]); + + data += 64; + + cpia->state = STATE_LINES; + + break; + case STATE_LINES: + { + unsigned char *begin = data; + int found = 0; + + while (scratch_left(data)) { + if (*data == 0xFD) { + data++; + found = 1; + break; + } else if ((*data == 0xFF) && + (scratch_left(data) >= 3) && + (*(data + 1) == 0xFF) && + (*(data + 2) == 0xFF) && + (*(data + 3) == 0xFF)) { + data+=4; + cpia->curline = 144; + found = 1; + break; + } + + data++; + } +#if 0 +printk("line %d: scanned %d bytes\n", cpia->curline, data-begin); +#endif +if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) { + int i; + char *f = cpia->frame[cpia->curframe].data, *b = begin; + +#if 0 +printk("copying\n"); +#endif + + b+=2; + f+=(cpia->frame[cpia->curframe].width*3)*cpia->curline; + for (i = 0; i < 176; i++) + f[(i * 3) + 0] = + f[(i * 3) + 1] = + f[(i * 3) + 2] = + b[(i * 2)]; +} + if (found) { + cpia->curline++; + if (cpia->curline >= 144) { + wake_up(&cpia->wq); + cpia->state = STATE_SCANNING; + cpia->curline = 0; + cpia->curframe = -1; + done = 1; + } + } else { + data = begin; + done = 1; + } + + break; + } + } + } + + { + int l; + + l = scratch_left(data); + memmove(cpia->scratch, data, l); + cpia->scratchlen = l; + } +} + +static int cpia_isoc_irq(int status, void *__buffer, void *dev_id) +{ + struct usb_cpia *cpia = dev_id; + struct usb_device *dev = cpia->dev; + struct cpia_sbuf *sbuf; + int i; + char *p; + + if (!cpia->streaming) { + printk("oops, not streaming, but interrupt\n"); + return 0; + } + + if (cpia->curframe < 0) { + if (cpia->frame[0].state == FRAME_READY) { + cpia->curframe = 0; + cpia->frame[0].state = FRAME_GRABBING; +printk("capturing to frame 0\n"); + } else if (cpia->frame[1].state == FRAME_READY) { + cpia->curframe = 1; + cpia->frame[1].state = FRAME_GRABBING; +printk("capturing to frame 1\n"); + } else +printk("no frame available\n"); + } + + sbuf = &cpia->sbuf[cpia->receivesbuf]; + + uhci_unsched_isochronous(dev, sbuf->isodesc); + + /* Do something to it now */ + sbuf->len = uhci_compress_isochronous(dev, sbuf->isodesc); + + if (sbuf->len) + printk("%d bytes received\n", sbuf->len); + + if (sbuf->len && cpia->curframe >= 0) { + if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) { + printk("overflow!\n"); + return 0; + } + memcpy(cpia->scratch + cpia->scratchlen, sbuf->data, sbuf->len); + cpia->scratchlen += sbuf->len; + + cpia_parse_data(cpia); + } + + /* Reschedule this block of Isochronous desc */ + uhci_sched_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc); + + /* Move to the next one */ + cpia->receivesbuf = (cpia->receivesbuf + 1) % 3; + + return 1; +} + +int cpia_init_isoc(struct usb_cpia *cpia) +{ + struct usb_device *dev = cpia->dev; + + cpia->receivesbuf = 0; + +#if 0 + cpia->parsesbuf = 0; + cpia->parsepos = 0; +#endif + cpia->scratchlen = 0; + cpia->curline = 0; + cpia->state = STATE_SCANNING; + + /* Allocate all of the memory necessary */ + cpia->sbuf[0].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); + cpia->sbuf[1].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); + cpia->sbuf[2].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); + + printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc); + printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc); + printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc); + + /* Schedule the queues */ + uhci_sched_isochronous(dev, cpia->sbuf[0].isodesc, NULL); + uhci_sched_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); + uhci_sched_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc); + + if (usb_set_interface(cpia->dev, 1, 3)) { + printk("cpia_set_interface error\n"); + return -EINVAL; + } + + usb_cpia_startstreamcap(cpia->dev); + + cpia->streaming = 1; + + return 0; +} + +void cpia_stop_isoc(struct usb_cpia *cpia) +{ + struct usb_device *dev = cpia->dev; + + if (!cpia->streaming) + return; + + cpia->streaming = 0; + + /* Stop the streaming */ + usb_cpia_endstreamcap(cpia->dev); + + /* Set packet size to 0 */ + if (usb_set_interface(cpia->dev, 1, 0)) { + printk("cpia_set_interface error\n"); + return -EINVAL; + } + + /* Unschedule all of the iso td's */ + uhci_unsched_isochronous(dev, cpia->sbuf[2].isodesc); + uhci_unsched_isochronous(dev, cpia->sbuf[1].isodesc); + uhci_unsched_isochronous(dev, cpia->sbuf[0].isodesc); + + /* Delete them all */ + uhci_delete_isochronous(dev, cpia->sbuf[2].isodesc); + uhci_delete_isochronous(dev, cpia->sbuf[1].isodesc); + uhci_delete_isochronous(dev, cpia->sbuf[0].isodesc); +} + +/* Video 4 Linux API */ +static int cpia_open(struct video_device *dev, int flags) +{ + struct usb_cpia *cpia = (struct usb_cpia *)dev; + +printk("cpia_open\n"); + + cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); + if (!cpia->fbuf) + return -ENOMEM; + + cpia->frame[0].state = FRAME_DONE; + cpia->frame[1].state = FRAME_DONE; + + cpia->frame[0].data = cpia->fbuf; + cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE; + printk("frame [0] @ %p\n", cpia->frame[0].data); + printk("frame [1] @ %p\n", cpia->frame[1].data); + + cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); + if (!cpia->sbuf[0].data) + return -ENOMEM; + + cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); + if (!cpia->sbuf[1].data) + return -ENOMEM; + + cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); + if (!cpia->sbuf[2].data) + return -ENOMEM; + + printk("sbuf[0] @ %p\n", cpia->sbuf[0].data); + printk("sbuf[1] @ %p\n", cpia->sbuf[1].data); + printk("sbuf[2] @ %p\n", cpia->sbuf[2].data); + + cpia->curframe = -1; + cpia->receivesbuf = 0; + + usb_cpia_initstreamcap(cpia->dev, 0, 60); + + cpia_init_isoc(cpia); + + return 0; +} + +static void cpia_close(struct video_device *dev) +{ + struct usb_cpia *cpia = (struct usb_cpia *)dev; + +printk("cpia_close\n"); + + cpia_stop_isoc(cpia); + + usb_cpia_finistreamcap(cpia->dev); + + rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE); + + kfree(cpia->sbuf[2].data); + kfree(cpia->sbuf[1].data); + kfree(cpia->sbuf[0].data); +} + +static int cpia_init_done(struct video_device *dev) +{ + return 0; +} + +static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +#if 0 + if (usb_set_interface(dev, 1, 3)) { + printk("cpia_set_interface error\n"); + return -EINVAL; + } + + if (usb_cpia_grab_frame(dev, 0)) { + printk("cpia_grab_frame error\n"); + return -EINVAL; + } + + if (usb_cpia_upload_frame(dev, 0)) { + printk("cpia_upload_frame error\n"); + return -EINVAL; + } + + buf = cpia->ibuf; + uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 176*144*4); + + { + printk("header magic: %X\n", (buf[0] << 8) + buf[1]); + + while ((buf[0] != 0x19) || (buf[1] != 0x68)) { + int i; + + printk("resync'ing\n"); + for (i=0;i<(176*144*4)-4;i++, buf++) + if ( + (buf[0] == 0xFF) && + (buf[1] == 0xFF) && + (buf[2] == 0xFF) && + (buf[3] == 0xFF)) { + buf+=4; + i+=4; + break; + } + + memmove(cpia->ibuf, buf, (176*144*4) - i); + uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->ibuf + (176*144*4) - i, i); + buf = cpia->ibuf; + +#if 0 + printk("header magic: %X\n", (buf[0] << 8) + buf[1]); +#endif + } + + printk("size: %d, sample: %d, order: %d\n", buf[16], buf[17], buf[18]); + printk("comp: %d, decimation: %d\n", buf[28], buf[29]); + printk("roi: top left: %d, %d bottom right: %d, %d\n", + buf[26] * 4, buf[24] * 8, + buf[27] * 4, buf[25] * 8); + + printk("vm->frame: %d\n", vm->frame); + + { + int i, i1; + char *b = buf + 64, *fbuf = &cpia->fbuffer[MAX_FRAME_SIZE * (vm->frame & 1)]; + for (i=0;i<144;i++) { +#if 0 + printk("line len: %d\n", (b[1] << 8) + b[0]); +#endif + b += 2; + for (i1=0;i1<176;i1++) { + fbuf[(i * vm->width * 3) + (i1 * 3)] = + fbuf[(i * vm->width * 3) + (i1 * 3) + 1] = + fbuf[(i * vm->width * 3) + (i1 * 3) + 2] = + b[i1 * 2]; +#if 0 + *((short *)&fbuf[(i * vm->width * 2) + (i1 * 2)]) = + ((b[i1 * 2] >> 3) << 11) + ((b[i1 * 2] >> 2) << 6) + (b[i1 * 2] >> 3); +#endif + } + b += (176 * 2) + 1; + } + } + + } + + if (usb_set_interface(dev, 1, 0)) { + printk("cpia_set_interface error\n"); + return -EINVAL; + } +#endif + +static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct usb_cpia *cpia = (struct usb_cpia *)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + + strcpy(b.name, "CPiA USB Camera"); + b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */; + b.channels = 1; + b.audios = 0; + b.maxwidth = 176 /* 352 */; + b.maxheight = 144 /* 240 */; + b.minwidth = 176 /* (Something small?) */; + b.minheight = 144 /* " " */; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Camera"); + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSCHAN: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v != 0) + return -EINVAL; + + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v.tuner) + return -EINVAL; + + strcpy(v.name, "Format"); + + v.rangelow = 0; + v.rangehigh = 0; + v.flags = 0; + v.mode = VIDEO_MODE_AUTO; + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v.tuner) + return -EINVAL; + + if (v.mode != VIDEO_MODE_AUTO) + return -EINVAL; + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p; + + p.colour = 0x8000; /* Damn British people :) */ + p.hue = 0x8000; + p.brightness = 180 << 8; /* XXX */ + p.contrast = 192 << 8; /* XXX */ + p.whiteness = 105 << 8; /* XXX */ +#if 0 + p.depth = 24; +#endif + p.depth = 16; + p.palette = VIDEO_PALETTE_YUYV; + + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + +printk("Attempting to set palette %d, depth %d\n", p.palette, p.depth); + +#if 0 + if (p.palette != VIDEO_PALETTE_YUYV) + return -EINVAL; + if (p.depth != 16) + return -EINVAL; +#endif + + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + +printk("VIDIOCSWIN\n"); + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if (vw.flags) + return -EINVAL; + if (vw.clipcount) + return -EINVAL; + if (vw.height != 176) + return -EINVAL; + if (vw.width != 144) + return -EINVAL; + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + +printk("VIDIOCGWIN\n"); + vw.x = 0; + vw.y = 0; + vw.width = 176; + vw.height = 144; + vw.chromakey = 0; + vw.flags = 0; + + if (copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + + memset(&vm, 0, sizeof(vm)); + vm.size = MAX_FRAME_SIZE * 2; + vm.frames = 2; + vm.offsets[0] = 0; + vm.offsets[1] = MAX_FRAME_SIZE; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) + return -EFAULT; + +printk("MCAPTURE\n"); +printk("frame: %d, size: %dx%d, format: %d\n", vm.frame, vm.width, vm.height, vm.format); + + if (vm.format != VIDEO_PALETTE_RGB24) + return -EINVAL; + + if ((vm.frame != 0) && (vm.frame != 1)) + return -EINVAL; + + cpia->frame[vm.frame].width = vm.width; + cpia->frame[vm.frame].height = vm.height; + + /* Mark it as free */ + cpia->frame[vm.frame].state = FRAME_READY; + + return 0; + } + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *)&frame, arg, sizeof(int))) + return -EFAULT; + + printk("syncing to frame %d\n", frame); + switch (cpia->frame[frame].state) { + case FRAME_UNUSED: + return -EINVAL; + case FRAME_READY: + case FRAME_GRABBING: + interruptible_sleep_on(&cpia->wq); + case FRAME_DONE: + cpia->frame[frame].state = FRAME_UNUSED; + break; + } + printk("synced to frame %d\n", frame); + return 0; + } + case VIDIOCCAPTURE: + return -EINVAL; + case VIDIOCGFBUF: + return -EINVAL; + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCKEY: + return 0; + case VIDIOCGFREQ: + return -EINVAL; + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + return -EINVAL; + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock) +{ + struct usb_cpia *cpia = (struct usb_cpia *)dev; + int len; + + printk("cpia_read: %d bytes\n", count); +#if 0 + len = cpia_capture(cpia, buf, count); + + return len; +#endif + return 0; +} + +static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct usb_cpia *cpia = (struct usb_cpia *)dev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + printk("mmap: %d (%X) bytes\n", size, size); + if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + return -EINVAL; + +#if 0 + if (!cpia->fbuffer) { + if ((cpia->fbuffer = rvmalloc(2 * MAX_FRAME_SIZE)) == NULL) + return -EINVAL; + } +#endif + + pos = (unsigned long)cpia->fbuf; + while (size > 0) + { + page = kvirt_to_phys(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + if (size > PAGE_SIZE) + size-=PAGE_SIZE; + else + size=0; + } + + return 0; +} + +static struct video_device cpia_template = { + "CPiA USB Camera", + VID_TYPE_CAPTURE, + VID_HARDWARE_CPIA, + cpia_open, + cpia_close, + cpia_read, + cpia_write, + NULL, + cpia_ioctl, + cpia_mmap, + cpia_init_done, + NULL, + 0, + 0 +}; + +static void usb_cpia_configure(struct usb_cpia *cpia) +{ + struct usb_device *dev = cpia->dev; + unsigned char version[4]; + unsigned char pnpid[6]; + unsigned char camerastat[8]; + unsigned char *buf; + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + + if (usb_cpia_get_version(dev, version)) { + printk("cpia_get_version error\n"); + return; + } + + printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n", + version[0], version[1], version[2], version[3]); + + if (usb_cpia_get_pnp_id(dev, pnpid)) { + printk("cpia_get_pnp_id error\n"); + return; + } + + printk("cpia: PnP Id: Vendor: %X, Product: %X, Revision: %X\n", + (pnpid[1] << 8) + pnpid[0], (pnpid[3] << 8) + pnpid[2], + (pnpid[5] << 8) + pnpid[4]); + + memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template)); + + init_waitqueue_head(&cpia->wq); + + if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) { + printk("video_register_device failed\n"); + return; + } + + if (usb_cpia_goto_hi_power(dev)) { + printk("cpia_goto_hi_power error\n"); + return; + } + + if (usb_cpia_get_vp_version(dev, version)) { + printk("cpia_get_vp_version error\n"); + return; + } + + printk("cpia: VP v%d rev %d\n", version[0], version[1]); + printk("cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]); + + /* Turn off continuous grab */ + if (usb_cpia_set_grab_mode(dev, 1)) { + printk("cpia_set_grab_mode error\n"); + return; + } + + /* Set up the sensor to be 30fps */ + if (usb_cpia_set_sensor_fps(dev, 1, 0)) { + printk("cpia_set_sensor_fps error\n"); + return; + } + + /* Set video into QCIF mode, and order into YUYV mode */ + if (usb_cpia_set_format(dev, CPIA_QCIF, 1, CPIA_YUYV)) { + printk("cpia_set_format error\n"); + return; + } + + /* Turn off compression */ + if (usb_cpia_set_compression(dev, 0, 0)) { + printk("cpia_set_compression error\n"); + return; + } + +#if 0 + if (usb_cpia_grab_frame(dev, 0)) { + printk("cpia_grab_frame error\n"); + return; + } + + if (usb_cpia_upload_frame(dev, 1)) { + printk("cpia_upload_frame error\n"); + return; + } + + buf = (void *)__get_free_page(GFP_KERNEL); + + { + int i; + for (i=0;i<448;i++) + buf[i]=0; + } + uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 448); + + { + int i; + for (i=0;i<448;i++) { + printk("%02X ", buf[i]); + if ((i % 16) == 15) + printk("\n"); + } + printk("\n"); + } + + free_page((unsigned long)buf); +#endif +} + +static int cpia_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_cpia *cpia; + + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return -1; + +#if 0 + /* We don't handle multi-interface hubs */ + if (dev->config[0].bNumInterfaces != 1) + return -1; +#endif + + interface = &dev->config[0].interface[0]; + + /* Is it a CPiA? */ +/* +Apr 24 17:49:04 bjorn kernel: Vendor: 0545 +Apr 24 17:49:04 bjorn kernel: Product: 8080 +*/ +/* + if (dev->descriptor.idVendor != 0x0545) + return -1; + if (dev->descriptor.idProduct != 0x8080) + return -1; + if (interface->bInterfaceClass != 0xFF) + return -1; + if (interface->bInterfaceSubClass != 0xFF) + return -1; +*/ + if (dev->descriptor.idVendor != 0x0553) + return -1; + if (dev->descriptor.idProduct != 0x0002) + return -1; + if (interface->bInterfaceClass != 0xFF) + return -1; + if (interface->bInterfaceSubClass != 0x00) + return -1; + +#if 0 + /* Multiple endpoints? What kind of mutant ninja-hub is this? */ + if (interface->bNumEndpoints != 1) + return -1; + + endpoint = &interface->endpoint[0]; + + /* Output endpoint? Curiousier and curiousier.. */ + if (!(endpoint->bEndpointAddress & 0x80)) + return -1; + + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((endpoint->bmAttributes & 3) != 3) + return -1; +#endif + + /* We found a CPiA */ + printk("USB CPiA camera found\n"); + + if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) { + printk("couldn't kmalloc cpia struct\n"); + return -1; + } + + memset(cpia, 0, sizeof(*cpia)); + + dev->private = cpia; + cpia->dev = dev; + + usb_cpia_configure(cpia); + +#if 0 + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), pport_irq, endpoint->bInterval, pport); +#endif + + return 0; +} + +static void cpia_disconnect(struct usb_device *dev) +{ + struct usb_cpia *cpia = dev->private; + + video_unregister_device(&cpia->vdev); + + /* Free the memory */ + kfree(cpia); +} + +static struct usb_driver cpia_driver = { + "cpia", + cpia_probe, + cpia_disconnect, + { NULL, NULL } +}; + +/* + * This should be a separate module. + */ +int usb_cpia_init(void) +{ + usb_register(&cpia_driver); + + return 0; +} + diff -ur --new-file old/linux/drivers/usb/cpia.h new/linux/drivers/usb/cpia.h --- old/linux/drivers/usb/cpia.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/cpia.h Thu May 13 23:18:09 1999 @@ -0,0 +1,139 @@ +#ifndef __LINUX_CPIA_H +#define __LINUX_CPIA_H + +#include + +#define USB_REQ_CPIA_GET_VERSION 0x01 +#define USB_REQ_CPIA_GET_PNP_ID 0x02 +#define USB_REQ_CPIA_GET_CAMERA_STATUS 0x03 +#define USB_REQ_CPIA_GOTO_HI_POWER 0x04 +#define USB_REQ_CPIA_GOTO_LO_POWER 0x05 +/* No 0x06 */ +#define USB_REQ_CPIA_GOTO_SUSPEND 0x07 +#define USB_REQ_CPIA_GOTO_PASS_THROUGH 0x08 +/* No 0x09 */ +#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS 0x0A + +#define USB_REQ_CPIA_READ_VC_REGS 0x21 +#define USB_REQ_CPIA_WRITE_BC_REG 0x22 +#define USB_REQ_CPIA_READ_MC_PORTS 0x23 +#define USB_REQ_CPIA_WRITE_MC_PORT 0x24 +#define USB_REQ_CPIA_SET_BAUD_RATE 0x25 +#define USB_REQ_CPIA_SET_ECP_TIMING 0x26 +#define USB_REQ_CPIA_READ_IDATA 0x27 +#define USB_REQ_CPIA_WRITE_IDATA 0x28 +#define USB_REQ_CPIA_GENERIC_CALL 0x29 +#define USB_REQ_CPIA_I2CSTART 0x2A +#define USB_REQ_CPIA_I2CSTOP 0x2B +#define USB_REQ_CPIA_I2CWRITE 0x2C +#define USB_REQ_CPIA_I2CREAD 0x2D + +#define USB_REQ_CPIA_GET_VP_VERSION 0xA1 +#define USB_REQ_CPIA_SET_COLOUR_PARAMS 0xA3 +#define USB_REQ_CPIA_SET_EXPOSURE 0xA4 +/* No 0xA5 */ +#define USB_REQ_CPIA_SET_COLOUR_BALANCE 0xA6 +#define USB_REQ_CPIA_SET_SENSOR_FPS 0xA7 +#define USB_REQ_CPIA_SET_VP_DEFAULTS 0xA8 +#define USB_REQ_CPIA_SET_APCOR 0xA9 +#define USB_REQ_CPIA_SET_FLICKER_CTRL 0xAA +#define USB_REQ_CPIA_SET_VL_OFFSET 0xAB + +#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS 0xB0 +#define USB_REQ_CPIA_GET_COLOUR_BALANCE 0xB1 +#define USB_REQ_CPIA_GET_EXPOSURE 0xB2 +#define USB_REQ_CPIA_SET_SENSOR_MATRIX 0xB3 + +#define USB_REQ_CPIA_COLOUR_BARS 0xBD +#define USB_REQ_CPIA_READ_VP_REGS 0xBE +#define USB_REQ_CPIA_WRITE_VP_REGS 0xBF + +#define USB_REQ_CPIA_GRAB_FRAME 0xC1 +#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2 +#define USB_REQ_CPIA_SET_GRAB_MODE 0xC3 +#define USB_REQ_CPIA_INIT_STREAM_CAP 0xC4 +#define USB_REQ_CPIA_FINI_STREAM_CAP 0xC5 +#define USB_REQ_CPIA_START_STREAM_CAP 0xC6 +#define USB_REQ_CPIA_END_STREAM_CAP 0xC7 +#define USB_REQ_CPIA_SET_FORMAT 0xC8 +#define USB_REQ_CPIA_SET_ROI 0xC9 +#define USB_REQ_CPIA_SET_COMPRESSION 0xCA +#define USB_REQ_CPIA_SET_COMPRESSION_TARGET 0xCB +#define USB_REQ_CPIA_SET_YUV_THRESH 0xCC +#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS 0xCD +#define USB_REQ_CPIA_DISCARD_FRAME 0xCE + +#define USB_REQ_CPIA_OUTPUT_RS232 0xE1 +#define USB_REQ_CPIA_ABORT_PROCESS 0xE4 +#define USB_REQ_CPIA_SET_DRAM_PAGE 0xE5 +#define USB_REQ_CPIA_START_DRAM_UPLOAD 0xE6 +#define USB_REQ_CPIA_START_DUMMY_STREAM 0xE8 +#define USB_REQ_CPIA_ABORT_STREAM 0xE9 +#define USB_REQ_CPIA_DOWNLOAD_DRAM 0xEA +/* #define USB_REQ_CPIA_NULL_CMD 0x?? */ + +#define CPIA_QCIF 0 +#define CPIA_CIF 1 + +#define CPIA_YUYV 0 +#define CPIA_UYVY 1 + +#define STREAM_BUF_SIZE (PAGE_SIZE * 4) + +#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) + +enum { + STATE_SCANNING, /* Scanning for start */ + STATE_HEADER, /* Parsing header */ + STATE_LINES, /* Parsing lines */ +}; + +struct usb_device; + +struct cpia_sbuf { + char *data; + int len; + void *isodesc; +}; + +enum { + FRAME_READY, /* Ready to grab into */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_UNUSED, /* Unused (no MCAPTURE) */ +}; + +struct cpia_frame { + char *data; + int width; + int height; + int state; +}; + +struct usb_cpia { + struct video_device vdev; + + /* Device structure */ + struct usb_device *dev; + + int streaming; + + char *fbuf; /* Videodev buffer area */ + + int curframe; + struct cpia_frame frame[2]; /* Double buffering */ + + int receivesbuf; /* Current receiving sbuf */ + struct cpia_sbuf sbuf[3]; /* Triple buffering */ + + int state; /* Current scanning state */ + int curline; + + char scratch[SCRATCH_BUF_SIZE]; + int scratchlen; + + wait_queue_head_t wq; +}; + +#endif + diff -ur --new-file old/linux/drivers/usb/hub.c new/linux/drivers/usb/hub.c --- old/linux/drivers/usb/hub.c Fri Apr 30 17:20:01 1999 +++ new/linux/drivers/usb/hub.c Sat May 15 03:32:32 1999 @@ -24,7 +24,7 @@ extern struct usb_operations uhci_device_operations; /* Wakes up khubd */ -static struct wait_queue *usb_hub_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait); static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; /* List of hubs needing servicing */ @@ -394,7 +394,7 @@ /* * This should be a separate module. */ -int hub_init(void) +int usb_hub_init(void) { int pid; diff -ur --new-file old/linux/drivers/usb/inits.h new/linux/drivers/usb/inits.h --- old/linux/drivers/usb/inits.h Fri Apr 30 17:20:30 1999 +++ new/linux/drivers/usb/inits.h Sat May 15 03:09:57 1999 @@ -2,5 +2,6 @@ int usb_kbd_init(void); int usb_audio_init(void); int hub_init(void); +int usb_acm_init(void); void hub_cleanup(void); void usb_mouse_cleanup(void); diff -ur --new-file old/linux/drivers/usb/mouse.c new/linux/drivers/usb/mouse.c --- old/linux/drivers/usb/mouse.c Fri Apr 30 17:20:49 1999 +++ new/linux/drivers/usb/mouse.c Sat May 15 03:32:32 1999 @@ -48,7 +48,7 @@ int present; /* this mouse is plugged in */ int active; /* someone is has this mouse's device open */ int ready; /* the mouse has changed state since the last read */ - struct wait_queue *wait; /* for polling */ + wait_queue_head_t wait; /* for polling */ struct fasync_struct *fasync; /* later, add a list here to support multiple mice */ /* but we will also need a list of file pointers to identify it */ @@ -277,7 +277,7 @@ misc_register(&usb_mouse); mouse->present = mouse->active = 0; - mouse->wait = NULL; + init_waitqueue_head(&mouse->wait); mouse->fasync = NULL; usb_register(&mouse_driver); diff -ur --new-file old/linux/drivers/usb/ohci-debug.c new/linux/drivers/usb/ohci-debug.c --- old/linux/drivers/usb/ohci-debug.c Tue May 11 19:04:03 1999 +++ new/linux/drivers/usb/ohci-debug.c Mon May 17 07:23:31 1999 @@ -80,17 +80,18 @@ printk(KERN_DEBUG " ohci ED:\n"); printk(KERN_DEBUG " status = 0x%x\n", stat); - printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d\n", + printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d%s\n", skip ? "Skip " : "", mps, - isoc ? "Isoc. " : "", + isoc ? " Isoc." : "", low_speed ? " LowSpd" : "", (dir == OHCI_ED_D_IN) ? " Input" : (dir == OHCI_ED_D_OUT) ? " Output" : "", halted ? " Halted" : "", toggle, endnum, - funcaddr); + funcaddr, + (stat & ED_ALLOCATED) ? " Allocated" : ""); printk(KERN_DEBUG " tail_td = 0x%x\n", ed->tail_td); printk(KERN_DEBUG " head_td = 0x%x\n", ed_head_td(ed)); printk(KERN_DEBUG " next_ed = 0x%x\n", ed->next_ed); @@ -108,19 +109,21 @@ printk(KERN_DEBUG " ohci TD hardware fields:\n"); printk(KERN_DEBUG " info = 0x%x\n", td->info); - printk(KERN_DEBUG " %s%s%s%d %s\n", + printk(KERN_DEBUG " %s%s%s%d %s %s%d\n", td_round ? "Rounding " : "", (td_dir == OHCI_TD_D_IN) ? "Input " : (td_dir == OHCI_TD_D_OUT) ? "Output " : (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "", "IntDelay ", td_int_delay, (td_toggle < 2) ? " " : - (td_toggle & 1) ? "Data1 " : "Data0 "); - printk(KERN_DEBUG " %s%d %s0x%x, %sAccessed, %sActive\n", - "ErrorCnt ", td_errcnt, - "ComplCode ", td_cc, + (td_toggle & 1) ? "Data1" : "Data0", + "ErrorCnt ", td_errcnt); + printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed, %sActive\n", + td_cc, td_cc_accessed(*td) ? "" : "Not ", td_active(*td) ? "" : "Not "); + + printk(KERN_DEBUG " %s\n", td_allocated(*td) ? "Allocated" : "Free"); printk(KERN_DEBUG " cur_buf = 0x%x\n", td->cur_buf); printk(KERN_DEBUG " next_td = 0x%x\n", td->next_td); diff -ur --new-file old/linux/drivers/usb/ohci-hcd.c new/linux/drivers/usb/ohci-hcd.c --- old/linux/drivers/usb/ohci-hcd.c Tue May 11 18:55:45 1999 +++ new/linux/drivers/usb/ohci-hcd.c Sat May 15 03:48:55 1999 @@ -63,8 +63,8 @@ -static struct wait_queue *control_wakeup; -static struct wait_queue *root_hub = NULL; +static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); +static DECLARE_WAIT_QUEUE_HEAD(root_hub); static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */ /* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */ @@ -145,7 +145,7 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct ohci * ohci = usb_dev->bus->hcpriv; int status; union ep_addr_ ep_addr; @@ -234,10 +234,14 @@ return usb_dev; } +/* FIXME! */ +#define sohci_bulk_msg NULL + struct usb_operations sohci_device_operations = { sohci_usb_allocate, sohci_usb_deallocate, sohci_control_msg, + sohci_bulk_msg, sohci_request_irq, }; @@ -1429,7 +1433,6 @@ #endif - int usb_mouse_init(void); #ifdef MODULE void cleanup_module(void) @@ -1460,16 +1463,6 @@ if (retval < 0) break; -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif - hub_init(); -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif @@ -1478,12 +1471,3 @@ } return retval; } - -void cleanup_drivers(void) -{ - hub_cleanup(); -#ifdef CONFIG_USB_MOUSE - usb_mouse_cleanup(); -#endif -} - diff -ur --new-file old/linux/drivers/usb/ohci.c new/linux/drivers/usb/ohci.c --- old/linux/drivers/usb/ohci.c Tue May 11 19:27:04 1999 +++ new/linux/drivers/usb/ohci.c Mon May 17 07:23:31 1999 @@ -29,7 +29,7 @@ * * No filesystems were harmed in the development of this code. * - * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $ + * $Id: ohci.c,v 1.43 1999/05/16 22:35:24 greg Exp $ */ #include @@ -57,33 +57,32 @@ static int apm_resume = 0; #endif -static struct wait_queue *ohci_configure = NULL; +static DECLARE_WAIT_QUEUE_HEAD(ohci_configure); -#ifdef OHCI_TIMER -static struct timer_list ohci_timer; /* timer for root hub polling */ +#ifdef CONFIG_USB_OHCI_DEBUG +#define OHCI_DEBUG /* to make typing it easier.. */ #endif +#ifdef OHCI_DEBUG +int MegaDebug = 0; /* SIGUSR2 to the control thread toggles this */ +#endif -static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td) -{ - unsigned int status; - - status = td->info & OHCI_TD_CC; - - /* TODO Debugging code for TD failures goes here */ - - return status; -} /* ohci_td_result() */ +#ifdef OHCI_TIMER +static struct timer_list ohci_timer; /* timer for root hub polling */ +#endif static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; /* - * Add a TD to the end of the TD list on a given ED. If td->next_td - * points to any more TDs, they will be added as well (naturally). - * Otherwise td->next_td must be 0. + * Add a TD to the end of the TD list on a given ED. This function + * does NOT advance the ED's tail_td pointer beyond the given TD. To + * add multiple TDs, call this function once for each TD. Do not + * "simply" update tail_td yourself... This function does more than + * that. * - * The SKIP flag will be cleared after this function. + * If this ED is on the controller, you MUST set its SKIP flag before + * calling this function. * * Important! This function needs locking and atomicity as it works * in parallel with the HC's DMA. Locking ohci_edtd_lock while using @@ -93,54 +92,62 @@ */ static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed) { - /* don't let the HC pull anything from underneath us */ - ed->status |= OHCI_ED_SKIP; + struct ohci_td *dummy_td, *prev_td; + + if (ed->tail_td == 0) { + printk("eek! an ED without a dummy_td\n"); + } + + /* The ED's tail_td is constant, always pointing to the + * dummy_td. The reason the ED never processes the dummy is + * that it stops processing TDs as soon as head_td == tail_td. + * When it advances to this last dummy TD it conveniently stops. */ + dummy_td = bus_to_virt(ed->tail_td); - if (ed_head_td(ed) == 0) { /* empty list, put it on the head */ - set_ed_head_td(ed, virt_to_bus(td)); - ed->tail_td = 0; + /* Dummy's data pointer is used to point to the previous TD */ + if (ed_head_td(ed) != ed->tail_td) { + prev_td = (struct ohci_td *) dummy_td->data; } else { - struct ohci_td *tail, *head; - head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed)); - tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td); - if (!tail) { /* no tail, single element list */ - td->next_td = head->next_td; - head->next_td = virt_to_bus(td); - ed->tail_td = virt_to_bus(td); - } else { /* append to the list */ - td->next_td = tail->next_td; - tail->next_td = virt_to_bus(td); - ed->tail_td = virt_to_bus(td); - } + /* if the ED is empty, previous is meaningless */ + /* We'll be inserting into the head of the list */ + prev_td = NULL; } - /* save the ED link in each of the TDs added */ + /* Store the new back pointer and set up this TD's next */ + dummy_td->data = td; + td->next_td = ed->tail_td; + + /* Store the TD pointer back to the ED */ td->ed = ed; - while (td->next_td != 0) { - td = bus_to_virt(td->next_td); - td->ed = ed; - } - /* turn off the SKIP flag */ - ed->status &= ~OHCI_ED_SKIP; + if (!prev_td) { /* No previous TD? then insert us at the head */ + if (ed_head_td(ed) != ed->tail_td) + printk(KERN_DEBUG "Suspicious ED...\n"); + set_ed_head_td(ed, virt_to_bus(td)); /* put it on the ED */ + } else { + /* add the TD to the end */ + prev_td->next_td = virt_to_bus(td); + } } /* ohci_add_td_to_ed() */ inline void ohci_start_control(struct ohci *ohci) { /* tell the HC to start processing the control list */ - writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); + writel_set(OHCI_USB_CLE, &ohci->regs->control); + writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); } inline void ohci_start_bulk(struct ohci *ohci) { /* tell the HC to start processing the bulk list */ - writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); + writel_set(OHCI_USB_BLE, &ohci->regs->control); + writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); } inline void ohci_start_periodic(struct ohci *ohci) { - /* enable processing periodc transfers starting next frame */ + /* enable processing periodic (intr) transfers starting next frame */ writel_set(OHCI_USB_PLE, &ohci->regs->control); } @@ -152,6 +159,7 @@ /* * Add an ED to the hardware register ED list pointed to by hw_listhead_p + * This function only makes sense for Control and Bulk EDs. */ static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p) { @@ -172,11 +180,11 @@ writel(virt_to_bus(ed), hw_listhead_p); spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* ohci_add_ed() */ +} /* ohci_add_ed_to_hw() */ /* - * Put another control ED on the controller's list + * Put a control ED on the controller's list */ void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed) { @@ -184,37 +192,146 @@ ohci_start_control(ohci); } /* ohci_add_control_ed() */ +/* + * Put a bulk ED on the controller's list + */ +void ohci_add_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_add_ed_to_hw(ed, &ohci->regs->ed_bulkhead); + ohci_start_bulk(ohci); +} /* ohci_add_bulk_ed() */ -#if 0 /* - * Put another control ED on the controller's list + * Put a periodic ED on the appropriate list given the period. */ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period) { - ohci_add_ed_to_hw(ed, /* XXX */); + struct ohci_ed *int_ed; + unsigned long flags; + + /* + * Pick a good frequency endpoint based on the requested period + */ + int_ed = &ohci->root_hub->ed[ms_to_ed_int(period)]; +#ifdef OHCI_DEBUG + printk("usb-ohci: Using INT ED queue %d for %dms period\n", + ms_to_ed_int(period), period); +#endif + + spin_lock_irqsave(&ohci_edtd_lock, flags); + /* + * Insert this ED at the front of the list. + */ + ed->next_ed = int_ed->next_ed; + int_ed->next_ed = virt_to_bus(ed); + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); + ohci_start_periodic(ohci); -} /* ohci_add_control_ed() */ +} /* ohci_add_periodic_ed() */ + +/* + * Put an isochronous ED on the controller's list + */ +inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_add_periodic_ed(ohci, ed, 1); +} + + +/* + * This will be used for the interrupt to wake us up on the next SOF + */ +DECLARE_WAIT_QUEUE_HEAD(start_of_frame_wakeup); + +/* + * Guarantee that an ED is safe to be modified by the HCD (us). + * + * This function can NOT be called from an interrupt. + */ +void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type) +{ + __u32 hw_listcurrent; + + /* tell the controller to skip this ED */ + ed->status |= OHCI_ED_SKIP; + + switch (ed_type) { + case HCD_ED_CONTROL: + hw_listcurrent = readl(regs->ed_controlcurrent); + break; + case HCD_ED_BULK: + hw_listcurrent = readl(regs->ed_bulkcurrent); + break; + case HCD_ED_ISOC: + case HCD_ED_INT: + hw_listcurrent = readl(regs->ed_periodcurrent); + break; + default: + return; + } + + /* + * If the HC is processing this ED we need to wait until the + * at least the next frame. + */ + if (virt_to_bus(ed) == hw_listcurrent) { + DECLARE_WAITQUEUE(wait, current); + +#ifdef OHCI_DEBUG + printk("Waiting a frame for OHC to finish with ED %p\n", ed); #endif + add_wait_queue(&start_of_frame_wakeup, &wait); + + /* clear the SOF interrupt status and enable it */ + writel(OHCI_INTR_SF, ®s->intrstatus); + writel(OHCI_INTR_SF, ®s->intrenable); + + schedule_timeout(HZ/10); + + remove_wait_queue(&start_of_frame_wakeup, &wait); + } + + return; /* The ED is now safe */ +} /* ohci_wait_for_ed_safe() */ + /* - * Remove an ED from the HC list whos bus headpointer is pointed to - * by hw_listhead_p + * Remove an ED from the HC's list. + * This function can ONLY be used for Control or Bulk EDs. * * Note that the SKIP bit is left on in the removed ED. */ -void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) +void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_type) { unsigned long flags; + struct ohci_regs *regs = ohci->regs; struct ohci_ed *cur; __u32 bus_ed = virt_to_bus(ed); __u32 bus_cur; + __u32 *hw_listhead_p; if (ed == NULL || !bus_ed) return; - /* tell the controller this skip ED */ - ed->status |= OHCI_ED_SKIP; + switch (ed_type) { + case HCD_ED_CONTROL: + hw_listhead_p = ®s->ed_controlhead; + break; + case HCD_ED_BULK: + hw_listhead_p = ®s->ed_bulkhead; + break; + default: + printk("Unknown HCD ED type %d.\n", ed_type); + return; + } + + /* + * Tell the controller to this skip ED and make sure it is not the + * being accessed by the HC as we speak. + */ + ohci_wait_for_ed_safe(regs, ed, ed_type); bus_cur = readl(hw_listhead_p); @@ -232,7 +349,7 @@ struct ohci_ed *prev; /* walk the list and unlink the ED if found */ - for (;;) { + do { prev = cur; cur = bus_to_virt(cur->next_ed); @@ -241,17 +358,14 @@ prev->next_ed = cur->next_ed; break; } - - if (cur->next_ed == 0) - break; - } + } while (cur->next_ed != 0); } /* clear any links from the ED for safety */ ed->next_ed = 0; spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* ohci_remove_ed_from_hw() */ +} /* ohci_remove_norm_ed_from_hw() */ /* * Remove an ED from the controller's control list. Note that the SKIP bit @@ -259,7 +373,7 @@ */ inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed) { - ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead); + ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_CONTROL); } /* @@ -268,7 +382,7 @@ */ inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) { - ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead); + ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK); } @@ -321,7 +435,8 @@ td->next_td = 0; /* remove the TDs links */ td->ed = NULL; - /* TODO return this TD to the pool of free TDs */ + /* return this TD to the pool of free TDs */ + ohci_free_td(td); /* unset the "skip me bit" in this ED */ ed->status &= ~OHCI_ED_SKIP; @@ -332,15 +447,21 @@ /* * Get a pointer (virtual) to an available TD from the given device's - * pool. - * - * Return NULL if none are left. + * pool. Return NULL if none are left. */ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev) { int idx; +#if 0 + printk(KERN_DEBUG "in ohci_get_free_td()\n"); +#endif + + /* FIXME: this is horribly inefficient */ for (idx=0; idx < NUM_TDS; idx++) { +#if 0 + show_ohci_td(&dev->td[idx]); +#endif if (!td_allocated(dev->td[idx])) { struct ohci_td *new_td = &dev->td[idx]; /* zero out the TD */ @@ -353,12 +474,53 @@ } } - printk("usb-ohci error: unable to allocate a TD\n"); + printk("usb-ohci: unable to allocate a TD\n"); return NULL; } /* ohci_get_free_td() */ /* + * Get a pointer (virtual) to an available TD from the given device's + * pool. Return NULL if none are left. + */ +static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev) +{ + int idx; + + /* FIXME: this is horribly inefficient */ + for (idx=0; idx < NUM_EDS; idx++) { + if (!ed_allocated(dev->ed[idx])) { + struct ohci_ed *new_ed = &dev->ed[idx]; + /* zero out the ED */ + memset(new_ed, 0, sizeof(*new_ed)); + /* all new EDs start with the SKIP bit set */ + new_ed->status |= OHCI_ED_SKIP; + /* mark it as allocated */ + allocate_ed(new_ed); + return new_ed; + } + } + + printk("usb-ohci: unable to allocate an ED\n"); + return NULL; +} /* ohci_get_free_ed() */ + + +void ohci_free_ed(struct ohci_ed *ed) +{ + if (!ed) + return; + + if (ed->tail_td == 0) { + printk("yikes! an ED without a dummy_td\n"); + } else + ohci_free_td((struct ohci_td *)bus_to_virt(ed->tail_td)); + + ed->status &= ~(__u32)ED_ALLOCATED; +} /* ohci_free_ed() */ + + +/* * Initialize a TD * * dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP @@ -379,10 +541,58 @@ td->dev_id = dev_id; td->completed = completed; +#if 0 + printk(KERN_DEBUG "ohci_fill_new_td created:\n"); + show_ohci_td(td); +#endif + return td; } /* ohci_fill_new_td() */ +/* + * Initialize a new ED on device dev, including allocating and putting the + * dummy tail_td on its queue if it doesn't already have one. Any + * TDs on this ED other than the dummy will be lost (so there better + * not be any!). This assumes that the ED is Allocated and will + * force the Allocated bit on. + */ +struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed, int maxpacketsize, int lowspeed, int endp_id, int isoc_tds) +{ + struct ohci_td *dummy_td; + + if (ed_head_td(ed) != ed->tail_td) + printk("Reusing a non-empty ED %p!\n", ed); + + if (!ed->tail_td) { + dummy_td = ohci_get_free_td(dev); + if (dummy_td == NULL) { + printk("Error allocating dummy TD for ED %p\n", ed); + return NULL; /* no dummy available! */ + } + make_dumb_td(dummy_td); /* flag it as a dummy */ + ed->tail_td = virt_to_bus(dummy_td); + } else { + dummy_td = bus_to_virt(ed->tail_td); + if (!td_dummy(*dummy_td)) + printk("ED %p's dummy %p is screwy\n", ed, dummy_td); + } + + /* set the head TD to the dummy and clear the Carry & Halted bits */ + ed->_head_td = ed->tail_td; + + ed->status = \ + ed_set_maxpacket(maxpacketsize) | + ed_set_speed(lowspeed) | + (endp_id & 0x7ff) | + ((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC); + allocate_ed(ed); + ed->next_ed = 0; + + return ed; +} /* ohci_fill_ed() */ + + /********************************** * OHCI interrupt list operations * **********************************/ @@ -404,70 +614,51 @@ struct ohci_td *td; struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ - /* - * Pick a good frequency endpoint based on the requested period - */ - interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)]; + /* Get an ED and TD */ + interrupt_ed = ohci_get_free_ed(dev); + if (!interrupt_ed) { + printk("Out of EDs on device %p in ohci_request_irq\n", dev); + return -1; + } + + td = ohci_get_free_td(dev); + if (!td) { + printk("Out of TDs in ohci_request_irq\n"); + ohci_free_ed(interrupt_ed); + return -1; + } /* * Set the max packet size, device speed, endpoint number, usb * device number (function address), and type of TD. - * - * FIXME: Isochronous transfers need a pool of special 32 byte - * TDs (32 byte aligned) in order to be supported. */ - interrupt_ed->status = \ - ed_set_maxpacket(usb_maxpacket(pipe)) | - ed_set_speed(usb_pipeslow(pipe)) | - usb_pipe_endpdev(pipe) | - OHCI_ED_F_NORM; - - td = ohci_get_free_td(dev); - /* FIXME: check for NULL */ + ohci_fill_ed(dev, interrupt_ed, usb_maxpacket(pipe), usb_pipeslow(pipe), + usb_pipe_endpdev(pipe), 0 /* normal TDs */); /* Fill in the TD */ ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)), TOGGLE_AUTO, OHCI_TD_ROUND, - dev->data, DATA_BUF_LEN, + &dev->data, DATA_BUF_LEN, dev_id, handler); /* - * TODO: be aware that OHCI won't advance out of the 4kb - * page cur_buf started in. It'll wrap around to the start - * of the page... annoying or useful? you decide. - * - * We should make sure dev->data doesn't cross a page... + * TODO: be aware of how the OHCI controller deals with DMA + * spanning more than one page. */ - /* FIXME: this just guarantees that its the end of the list */ - td->next_td = 0; + /* + * Put the TD onto our ED and make sure its ready to run + */ + ohci_add_td_to_ed(td, interrupt_ed); + interrupt_ed->status &= ~OHCI_ED_SKIP; + ohci_unhalt_ed(interrupt_ed); /* Linus did this. see asm/system.h; scary concept... I don't * know if its needed here or not but it won't hurt. */ wmb(); - /* - * Put the TD onto our ED - */ - { - unsigned long flags; - spin_lock_irqsave(&ohci_edtd_lock, flags); - ohci_add_td_to_ed(td, interrupt_ed); - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - } - -#if 0 /* Assimilate the new ED into the collective */ - /* - * When dynamic ED allocation is done, this call will be - * useful. For now, the correct ED already on the - * controller's proper periodic ED lists was chosen above. - */ ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); -#else - /* enable periodic (interrupt) transfers on the HC */ - ohci_start_periodic(dev->ohci); -#endif return 0; } /* ohci_request_irq() */ @@ -476,7 +667,7 @@ /* * Control thread operations: */ -static struct wait_queue *control_wakeup; +static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); /* * This is the handler that gets called when a control transaction @@ -486,6 +677,12 @@ */ static int ohci_control_completed(int stats, void *buffer, void *dev_id) { + /* pass the TDs completion status back to control_msg */ + if (dev_id) { + int *completion_status = (int *)dev_id; + *completion_status = stats; + } + wake_up(&control_wakeup); return 0; } /* ohci_control_completed() */ @@ -502,44 +699,46 @@ * - The command itself * - An optional data phase (if len > 0) * - Status complete phase + * + * This function can NOT be called from an interrupt. */ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len) { struct ohci_device *dev = usb_to_ohci(usb); - /* - * ideally dev->ed should be linked into the root hub's - * control_ed list and used instead of just using it directly. - * This could present a problem as is with more than one - * device. (but who wants to use a keyboard AND a mouse - * anyways? ;) - */ - struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL]; + struct ohci_ed *control_ed = ohci_get_free_ed(dev); struct ohci_td *setup_td, *data_td, *status_td; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int completion_status = -1; -#if 0 - printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); +#ifdef OHCI_DEBUG + printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); #endif + if (!control_ed) { + printk("usb-ohci: couldn't get ED for dev %p\n", dev); + return -1; + } + + /* get a TD to send this control message with */ + setup_td = ohci_get_free_td(dev); + if (!setup_td) { + printk("usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev); + ohci_free_ed(control_ed); + return -1; + } /* * Set the max packet size, device speed, endpoint number, usb * device number (function address), and type of TD. * */ - control_ed->status = \ - ed_set_maxpacket(usb_maxpacket(pipe)) | - ed_set_speed(usb_pipeslow(pipe)) | - usb_pipe_endpdev(pipe) | - OHCI_ED_F_NORM; + ohci_fill_ed(dev, control_ed, usb_maxpacket(pipe), usb_pipeslow(pipe), + usb_pipe_endpdev(pipe), 0 /* normal TDs */); /* * Build the control TD */ - /* get a TD to send this control message with */ - setup_td = ohci_get_free_td(dev); - /* TODO check for NULL */ - /* * Set the not accessed condition code, allow odd sized data, * and set the data transfer type to SETUP. Setup DATA always @@ -555,7 +754,13 @@ NULL, NULL); /* allocate the next TD */ - data_td = ohci_get_free_td(dev); /* TODO check for NULL */ + data_td = ohci_get_free_td(dev); + if (!data_td) { + printk("usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev); + ohci_free_td(setup_td); + ohci_free_ed(control_ed); + return -1; + } /* link to the next TD */ setup_td->next_td = virt_to_bus(data_td); @@ -570,48 +775,59 @@ NULL, NULL); /* - * XXX we should check that the data buffer doesn't - * cross a 4096 byte boundary. If so, it needs to be - * copied into a single 4096 byte aligned area for the - * OHCI's TD logic to see it all, or multiple TDs need - * to be made for each page. + * TODO: Normal TDs can transfer up to 8192 bytes on OHCI. + * However, for that to happen, the data must -start- + * on a nice 4kb page. We need to check for data + * sizes > 4096 and, if they cross more than two 4096 + * byte pages of memory one or more additional TDs + * will need to be created. (repeat doing this in a + * loop until all of the DATA is on a TD) * - * It's not likely a control transfer will run into - * this problem.. (famous last words) + * Control transfers are -highly unlikely- to need to + * transfer this much data.. but who knows.. sadistic + * hardware is sure to exist. */ status_td = ohci_get_free_td(dev); /* TODO check for NULL */ + if (!status_td) { + printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev); + ohci_free_td(setup_td); + ohci_free_td(data_td); + ohci_free_ed(control_ed); + return -1; + } + data_td->next_td = virt_to_bus(status_td); } else { status_td = data_td; /* no data_td, use it for status */ } - /* The control status packet always uses a DATA1 */ + /* The control status packet always uses a DATA1 + * Give "dev_id" the address of completion_status so that the + * TDs status can be passed back to us from the IRQ. */ ohci_fill_new_td(status_td, td_set_dir_in(usb_pipeout(pipe) | (len == 0)), TOGGLE_DATA1, - 0, - NULL, 0, - NULL, ohci_control_completed); + 0 /* flags */, + NULL /* data */, 0 /* data len */, + &completion_status, ohci_control_completed); status_td->next_td = 0; /* end of TDs */ /* - * Start the control transaction.. - */ - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&control_wakeup, &wait); - - /* * Add the chain of 2-3 control TDs to the control ED's TD list */ - { - unsigned long flags; - spin_lock_irqsave(&ohci_edtd_lock, flags); - ohci_add_td_to_ed(setup_td, control_ed); - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - } + spin_lock_irqsave(&ohci_edtd_lock, flags); + control_ed->status |= OHCI_ED_SKIP; + ohci_add_td_to_ed(setup_td, control_ed); + if (data_td != status_td) + ohci_add_td_to_ed(data_td, control_ed); + ohci_add_td_to_ed(status_td, control_ed); + control_ed->status &= ~OHCI_ED_SKIP; + ohci_unhalt_ed(control_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); -#if 0 +#ifdef OHCI_DEBUG + if (MegaDebug) { /* complete transaction debugging output (before) */ printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed)); show_ohci_ed(control_ed); @@ -623,48 +839,55 @@ } printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td)); show_ohci_td(status_td); + printk(KERN_DEBUG " Controller Status:\n"); + show_ohci_status(dev->ohci); + } #endif + /* + * Start the control transaction.. + */ + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + /* Give the ED to the HC */ ohci_add_control_ed(dev->ohci, control_ed); - /* FIXME: - * this should really check to see that the transaction completed. - */ schedule_timeout(HZ/10); remove_wait_queue(&control_wakeup, &wait); -#if 0 +#ifdef OHCI_DEBUG + if (MegaDebug) { /* complete transaction debugging output (after) */ - printk(KERN_DEBUG " (after) Control ED:\n"); + printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); show_ohci_ed(control_ed); - printk(KERN_DEBUG " (after) Setup TD:\n"); + printk(KERN_DEBUG " *after* Setup TD %lx:\n", virt_to_bus(setup_td)); show_ohci_td(setup_td); if (data_td != status_td) { - printk(KERN_DEBUG " (after) Data TD:\n"); + printk(KERN_DEBUG " *after* Data TD %lx:\n", virt_to_bus(data_td)); show_ohci_td(data_td); } - printk(KERN_DEBUG " (after) Status TD:\n"); + printk(KERN_DEBUG " *after* Status TD %lx:\n", virt_to_bus(status_td)); show_ohci_td(status_td); + printk(KERN_DEBUG " *after* Controller Status:\n"); + show_ohci_status(dev->ohci); + } #endif - /* clean up incase it failed */ - /* XXX only do this if their ed pointer still points to control_ed - * incase they've been reclaimed and used by something else - * already. -greg */ - ohci_remove_td_from_ed(setup_td, control_ed); - ohci_remove_td_from_ed(data_td, control_ed); - ohci_remove_td_from_ed(status_td, control_ed); - - /* remove the control ED */ + /* clean up */ + ohci_free_td(setup_td); + if (data_td != status_td) + ohci_free_td(data_td); + ohci_free_td(status_td); + /* remove the control ED from the HC */ ohci_remove_control_ed(dev->ohci, control_ed); + ohci_free_ed(control_ed); /* return it to the pool */ #if 0 printk(KERN_DEBUG "leaving ohci_control_msg\n"); #endif - - return ohci_td_result(dev, status_td); + return completion_status; } /* ohci_control_msg() */ @@ -675,6 +898,7 @@ { struct usb_device *usb_dev; struct ohci_device *dev; + int idx; /* * Allocate the generic USB device @@ -696,6 +920,12 @@ memset(dev, 0, sizeof(*dev)); + /* Initialize all EDs in a new device with the skip flag so that + * they are ignored by the controller until set otherwise. */ + for (idx = 0; idx < NUM_EDS; ++idx) { + dev->ed[idx].status |= OHCI_ED_SKIP; + } + /* * Link them together */ @@ -728,6 +958,8 @@ return 0; } +/* FIXME! */ +#define ohci_bulk_msg NULL /* * functions for the generic USB driver @@ -736,6 +968,7 @@ ohci_usb_allocate, ohci_usb_deallocate, ohci_control_msg, + ohci_bulk_msg, ohci_request_irq, }; @@ -749,10 +982,10 @@ */ static int reset_hc(struct ohci *ohci) { - int timeout = 1000; /* prevent an infinite loop */ + int timeout = 10000; /* prevent an infinite loop */ #if 0 - printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci); + printk(KERN_INFO "usb-ohci: resetting HC %p\n", ohci); #endif writel(~0x0, &ohci->regs->intrdisable); /* Disable HC interrupts */ @@ -767,7 +1000,7 @@ udelay(1); } - printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci); + printk(KERN_INFO "usb-ohci: HC %p reset.\n", ohci); return 0; } /* reset_hc() */ @@ -780,6 +1013,7 @@ { int ret = 0; int fminterval; + __u32 what_to_enable; fminterval = readl(&ohci->regs->fminterval) & 0x3fff; #if 0 @@ -809,9 +1043,13 @@ * useful for debugging and as a bus heartbeat. -greg */ /* Choose the interrupts we care about */ - writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */ - OHCI_INTR_WDH | OHCI_INTR_FNO, - &ohci->regs->intrenable); + what_to_enable = OHCI_INTR_MIE | +#ifdef OHCI_RHSC_INT + OHCI_INTR_RHSC | +#endif + /* | OHCI_INTR_FNO */ + OHCI_INTR_WDH; + writel( what_to_enable, &ohci->regs->intrenable); /* Enter the USB Operational state & start the frames a flowing.. */ writel_set(OHCI_USB_OPER, &ohci->regs->control); @@ -819,6 +1057,18 @@ /* Enable control lists */ writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control); + /* Force global power enable -gal@cs.uni-magdeburg.de */ + /* + * This turns on global power switching for all the ports + * and tells the HC that all of the ports should be powered on + * all of the time. + * + * TODO: This could be battery draining for laptops.. We + * should implement power switching. + */ + writel_set( OHCI_ROOT_A_NPS, &ohci->regs->roothub.a ); + writel_mask( ~((__u32)OHCI_ROOT_A_PSM), &ohci->regs->roothub.a ); + /* Turn on power to the root hub ports (thanks Roman!) */ writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status ); @@ -846,7 +1096,7 @@ /* * Wait for the reset to complete. */ - wait_ms(10); + wait_ms(20); /* check port status to see that the reset completed */ status = readl(&ohci->regs->roothub.portstatus[port]); @@ -871,10 +1121,12 @@ struct usb_device *usb_dev; struct ohci_device *dev; /* memory I/O address of the port status register */ - void *portaddr = &ohci->regs->roothub.portstatus[port]; + __u32 *portaddr = &ohci->regs->roothub.portstatus[port]; int portstatus; - printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port); +#ifdef OHCI_DEBUG + printk(KERN_DEBUG "ohci_connect_change on port %d\n", port); +#endif /* * Because of the status change we have to forget @@ -888,6 +1140,14 @@ /* disable the port if nothing is connected */ if (!(portstatus & PORT_CCS)) { writel(PORT_CCS, portaddr); + /* We need to reset the CSC bit -after- disabling the + * port because it causes the CSC bit to come on + * again... */ + wait_ms(20); + writel(PORT_CSC, portaddr); +#ifdef OHCI_DEBUG + printk(KERN_DEBUG "ohci port %d disabled, nothing connected.\n", port); +#endif return; } @@ -928,15 +1188,18 @@ struct ohci_regs *regs = ohci->regs; int num = 0; int maxport = readl(&ohci->regs->roothub) & 0xff; + __u32 rh_change_flags = PORT_CSC | PORT_PESC; /* root hub status changes */ -#if 1 +#ifdef OHCI_DEBUG printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci); #endif do { - if (readl(®s->roothub.portstatus[num]) & PORT_CSC) { - /* reset the connect status change bit */ - writel(PORT_CSC, ®s->roothub.portstatus[num]); + __u32 *portstatus_p = ®s->roothub.portstatus[num]; + if (readl(portstatus_p) & rh_change_flags) { + /* acknowledge the root hub status changes */ + writel_set(rh_change_flags, portstatus_p); + /* disable the port if nothing is on it */ /* check the port for a nifty device */ ohci_connect_change(ohci, num); } @@ -962,8 +1225,8 @@ int maxport = ohci->root_hub->usb->maxchild; do { - if (readl(&ohci->regs->roothub.portstatus[num]) & - PORT_CSC) { + __u32 *portstatus_p = &ohci->regs->roothub.portstatus[num]; + if (readl(portstatus_p) & PORT_CSC) { if (waitqueue_active(&ohci_configure)) wake_up(&ohci_configure); return; @@ -1022,6 +1285,9 @@ while (td != NULL) { struct ohci_td *next_td = td->next_dl_td; + if (td_dummy(*td)) + printk("yikes! reaping a dummy TD\n"); + /* FIXME: munge td->info into a future standard status format */ /* Check if TD should be re-queued */ if ((td->completed != NULL) && @@ -1029,14 +1295,15 @@ { /* Mark the TD as active again: * Set the not accessed condition code - * FIXME: should this reset OHCI_TD_ERRCNT? + * Reset the Error count + * [FIXME: report errors to the device's driver] */ td->info |= OHCI_TD_CC_NEW; + clear_td_errorcount(td); /* point it back to the start of the data buffer */ td->cur_buf = virt_to_bus(td->data); - /* XXX disabled for debugging reasons right now.. */ /* insert it back on its ED */ ohci_add_td_to_ed(td, td->ed); } else { @@ -1051,9 +1318,6 @@ } /* ohci_reap_donelist() */ -#if 0 -static int in_int = 0; -#endif /* * Get annoyed at the controller for bothering us. * This pretty much follows the OHCI v1.0a spec, section 5.3. @@ -1065,19 +1329,10 @@ struct ohci_hcca *hcca = ohci->root_hub->hcca; __u32 status, context; -#if 0 - /* for debugging to keep IRQs from running away. */ - if (in_int >= 2) - return; - ++in_int; - return; -#endif - /* Save the status of the interrupts that are enabled */ status = readl(®s->intrstatus); status &= readl(®s->intrenable); - /* make context = the interrupt status bits that we care about */ if (hcca->donehead != 0) { context = OHCI_INTR_WDH; /* hcca donehead needs processing */ @@ -1107,6 +1362,10 @@ context &= ~OHCI_INTR_WDH; /* mark this as checked */ } +#ifdef OHCI_RHSC_INT + /* NOTE: this is very funky on some USB controllers (ie: it + * doesn't work right). Using the ohci_timer instead to poll + * the root hub is a much better choice. */ /* Process any root hub status changes */ if (context & OHCI_INTR_RHSC) { /* Wake the thread to process root hub events */ @@ -1119,10 +1378,17 @@ * The control thread will re-enable it after it has * checked the root hub status. */ - } else { - /* check the root hub status anyways. Some controllers - * might not generate the interrupt properly. (?) */ - ohci_root_hub_events(ohci); + } +#endif + + /* Start of Frame interrupts, used during safe ED removal */ + if (context & (OHCI_INTR_SF)) { + writel(OHCI_INTR_SF, ®s->intrstatus); + if (waitqueue_active(&start_of_frame_wakeup)) + wake_up(&start_of_frame_wakeup); + /* Do NOT mark the frame start interrupt as checked + * as we don't want to receive any more of them until + * asked. */ } /* Check those "other" pesky bits */ @@ -1151,8 +1417,8 @@ context &= ~OHCI_INTR_OC; /* mark this as checked */ } - /* Mask out any remaining unprocessed interrupts so we don't - * get any more of them. */ + /* Mask out any remaining unprocessed or unmasked interrupts + * so that we don't get any more of them. */ if (context & ~OHCI_INTR_MIE) { writel(context, ®s->intrdisable); } @@ -1260,40 +1526,38 @@ /* * Initialize the polling table to call interrupts at the - * intended intervals. + * intended intervals. Note that these EDs are just + * placeholders. They have their SKIP bit set and are used as + * list heads to insert real EDs onto. */ - dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]); + dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_1]); for (i = 1; i < NUM_INTS; i++) { - if (i & 1) + if (i & 16) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_32]); + if (i & 8) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_16]); - else if (i & 2) + if (i & 4) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_8]); - else if (i & 4) + if (i & 2) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_4]); - else if (i & 8) + if (i & 1) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_2]); - else if (i & 16) - dev->hcca->int_table[i] = - virt_to_bus(&dev->ed[ED_INT_1]); } /* - * Tell the controller where the control and bulk lists are + * Tell the controller where the control and bulk lists are. * The lists start out empty. */ writel(0, &ohci->regs->ed_controlhead); writel(0, &ohci->regs->ed_bulkhead); - /* - writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead); - writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead); - */ -#if 0 - printk(KERN_DEBUG "alloc_ohci(): controller\n"); +#ifdef OHCI_DEBUG + printk(KERN_INFO "alloc_ohci(): controller\n"); show_ohci_status(ohci); #endif @@ -1310,7 +1574,7 @@ */ static void release_ohci(struct ohci *ohci) { - printk(KERN_DEBUG "entering release_ohci %p\n", ohci); + printk(KERN_INFO "Releasing OHCI controller 0x%p\n", ohci); #ifdef OHCI_TIMER /* stop our timer */ @@ -1363,7 +1627,7 @@ * This thread doesn't need any user-level access, * so get rid of all of our resources.. */ - printk("ohci_control_thread code at %p\n", &ohci_control_thread); + printk(KERN_INFO "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread); exit_mm(current); exit_files(current); exit_fs(current); @@ -1376,7 +1640,7 @@ if (start_hc(ohci) < 0) { printk("usb-ohci: failed to start the controller\n"); release_ohci(ohci); - printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); + printk(KERN_INFO "leaving ohci_control_thread %p\n", __ohci); return 0; } @@ -1390,11 +1654,11 @@ ohci_check_configuration(ohci); /* re-enable root hub status change interrupts. */ -#if 0 +#ifdef OHCI_RHSC_INT writel(OHCI_INTR_RHSC, &ohci->regs->intrenable); #endif - printk(KERN_DEBUG "ohci-control thread sleeping\n"); + printk(KERN_INFO "ohci-control thread sleeping\n"); interruptible_sleep_on(&ohci_configure); #ifdef CONFIG_APM if (apm_resume) { @@ -1416,9 +1680,14 @@ spin_unlock_irq(¤t->sigmask_lock); if(signr == SIGUSR1) { - /* FIXME: have it do a full ed/td queue dump */ + /* TODO: have it do a full ed/td queue dump? */ printk(KERN_DEBUG "OHCI status dump:\n"); show_ohci_status(ohci); + } else if (signr == SIGUSR2) { + /* toggle mega TD/ED debugging output */ + MegaDebug = !MegaDebug; + printk(KERN_DEBUG "usb-ohci: Mega debugging %sabled.\n", + MegaDebug ? "en" : "dis"); } else { /* unknown signal, exit the thread */ break; @@ -1429,7 +1698,7 @@ reset_hc(ohci); release_ohci(ohci); - printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); + printk(KERN_INFO "ohci-control thread for 0x%p exiting\n", __ohci); return 0; } /* ohci_control_thread() */ @@ -1470,9 +1739,12 @@ #ifdef OHCI_TIMER /* * Inspired by Iñaky's driver. This function is a timer routine that - * is called OHCI_TIMER_FREQ times per second. It polls the root hub - * for status changes as on my system things are acting a bit odd at - * the moment.. + * is called every OHCI_TIMER_FREQ ms. It polls the root hub for + * status changes as on my system the RHSC interrupt just doesn't + * play well with others.. (so RHSC is turned off by default in this + * driver) + * [my controller is a "SiS 7001 USB (rev 16)"] + * -greg */ static void ohci_timer_func (unsigned long ohci_ptr) { @@ -1480,8 +1752,9 @@ ohci_root_hub_events(ohci); - /* press the snooze button... */ - mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ)); + /* set the next timer */ + mod_timer(&ohci_timer, jiffies + ((OHCI_TIMER_FREQ*HZ)/1000)); + } /* ohci_timer_func() */ #endif @@ -1507,9 +1780,10 @@ #ifdef OHCI_TIMER init_timer(&ohci_timer); - ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ); + ohci_timer.expires = jiffies + ((OHCI_TIMER_FREQ*HZ)/1000); ohci_timer.data = (unsigned long)ohci; ohci_timer.function = ohci_timer_func; + add_timer(&ohci_timer); #endif retval = -EBUSY; @@ -1518,8 +1792,8 @@ ohci->irq = irq; -#if 0 - printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n"); +#ifdef OHCI_DEBUG + printk(KERN_INFO "usb-ohci: forking ohci-control thread for 0x%p\n", ohci); #endif /* fork off the handler */ @@ -1535,7 +1809,7 @@ } release_ohci(ohci); -#if 0 +#ifdef OHCI_DEBUG printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base); #endif @@ -1577,6 +1851,11 @@ } MOD_INC_USE_COUNT; +#ifdef OHCI_DEBUG + printk("usb-ohci: Warning! Gobs of debugging output has been enabled.\n"); + printk(" Check your kern.debug logs for the bulk of it.\n"); +#endif + if (found_ohci(dev->irq, (void *) mem_base) < 0) { MOD_DEC_USE_COUNT; return -1; @@ -1644,18 +1923,6 @@ if (retval < 0) continue; - /* TODO check module params here to determine what to load */ - -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif - hub_init(); -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif @@ -1664,6 +1931,7 @@ } return retval; } /* ohci_init */ + /* vim:sw=8 */ diff -ur --new-file old/linux/drivers/usb/ohci.h new/linux/drivers/usb/ohci.h --- old/linux/drivers/usb/ohci.h Tue May 11 19:04:03 1999 +++ new/linux/drivers/usb/ohci.h Mon May 17 07:23:31 1999 @@ -6,7 +6,7 @@ * * (C) Copyright 1999 Gregory P. Smith * - * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $ + * $Id: ohci.h,v 1.24 1999/05/16 10:18:26 greg Exp $ */ #include @@ -37,7 +37,9 @@ struct ohci_td *next_dl_td; /* used during donelist processing */ void *data; /* virt. address of the the buffer */ usb_device_irq completed; /* Completion handler routine */ - int allocated; /* boolean: is this TD allocated? */ + int hcd_flags; /* Flags for the HCD: */ + /* bit0 = boolean: Is this TD allocated? */ + /* bit1 = boolean: Is this a dummy (end of list) TD? */ /* User or Device class driver specific fields */ void *dev_id; /* user defined pointer passed to irq handler */ @@ -59,6 +61,7 @@ #define td_force_toggle(b) (((b) | 2) << 24) #define OHCI_TD_ERRCNT (3 << 26) /* error count */ #define td_errorcount(td) (((td).info >> 26) & 3) +#define clear_td_errorcount(td) ((td)->info &= ~(__u32)OHCI_TD_ERRCNT) #define OHCI_TD_CC (0xf << 28) /* condition code */ #define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf) #define OHCI_TD_CC_NEW (OHCI_TD_CC) /* set this on all unaccessed TDs! */ @@ -68,9 +71,16 @@ #define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3)) #define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3)) -#define td_allocated(td) ((td).allocated) -#define allocate_td(td) ((td)->allocated = 1) -#define ohci_free_td(td) ((td)->allocated = 0) +/* + * Macros to use the td->hcd_flags field. + */ +#define td_allocated(td) ((td).hcd_flags & 1) +#define allocate_td(td) ((td)->hcd_flags |= 1) +#define ohci_free_td(td) ((td)->hcd_flags &= ~(__u32)1) + +#define td_dummy(td) ((td).hcd_flags & 2) +#define make_dumb_td(td) ((td)->hcd_flags |= 2) +#define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2) /* @@ -87,9 +97,14 @@ /* get the head_td */ #define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0) -/* save the carry flag while setting the head_td */ +/* save the carry & halted flag while setting the head_td */ #define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3)) +/* Control the ED's halted flag */ +#define ohci_halt_ed(ed) ((ed)->_head_td |= 1) +#define ohci_unhalt_ed(ed) ((ed)->_head_td &= ~(__u32)1) +#define ohci_ed_halted(ed) ((ed)->_head_td & 1) + #define OHCI_ED_SKIP (1 << 14) #define OHCI_ED_MPS (0x7ff << 16) /* FIXME: should cap at the USB max packet size [0x4ff] */ @@ -109,14 +124,14 @@ #define OHCI_ED_FA (0x7f) -/* NOTE: bits 27-31 of the status dword are reserved for the driver */ +/* NOTE: bits 27-31 of the status dword are reserved for the HCD */ /* * We'll use this status flag for to mark if an ED is in use by the - * driver or not. If the bit is set, it is used. - * - * FIXME: implement this! + * driver or not. If the bit is set, it is being used. */ -#define ED_USED (1 << 31) +#define ED_ALLOCATED (1 << 31) +#define ed_allocated(ed) ((ed).status & ED_ALLOCATED) +#define allocate_ed(ed) ((ed)->status |= ED_ALLOCATED) /* * The HCCA (Host Controller Communications Area) is a 256 byte @@ -182,16 +197,17 @@ /* .... */ +/* + * These are the index of the placeholder EDs for the root hub to + * build the interrupt transfer ED tree out of. + */ #define ED_INT_1 0 #define ED_INT_2 1 #define ED_INT_4 2 #define ED_INT_8 3 #define ED_INT_16 4 #define ED_INT_32 5 -#define ED_CONTROL 6 -#define ED_BULK 7 #define ED_ISO ED_INT_1 /* same as 1ms interrupt queue */ -#define ED_FIRST_AVAIL 8 /* first non-reserved ED */ /* * Given a period p in ms, convert it to the closest endpoint @@ -210,7 +226,9 @@ * This is the maximum number of root hub ports. I don't think we'll * ever see more than two as that's the space available on an ATX * motherboard's case, but it could happen. The OHCI spec allows for - * up to 15... (which is insane!) + * up to 15... (which is insane given that they each need to supply up + * to 500ma; that would be 7.5 amps!). I have seen a PCI card with 4 + * downstream ports on it. * * Although I suppose several "ports" could be connected directly to * internal laptop devices such as a keyboard, mouse, camera and @@ -254,15 +272,24 @@ } roothub; } __attribute((aligned(32))); +/* + * These are used by internal ED managing functions as a + * parameter to state the type of ED to deal with (when it matters). + */ +#define HCD_ED_ISOC (0) +#define HCD_ED_INT (1) +#define HCD_ED_CONTROL (2) +#define HCD_ED_BULK (3) + /* * Read a MMIO register and re-write it after ANDing with (m) */ -#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) ) +#define writel_mask(m, a) writel( (readl((unsigned long)(a))) & (__u32)(m), (unsigned long)(a) ) /* * Read a MMIO register and re-write it after ORing with (b) */ -#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) ) +#define writel_set(b, a) writel( (readl((unsigned long)(a))) | (__u32)(b), (unsigned long)(a) ) #define PORT_CCS (1) /* port current connect status */ @@ -289,6 +316,16 @@ #define OHCI_ROOT_CRWE (1 << 31) /* Clear RemoteWakeupEnable */ /* + * Root hub A register masks + */ +#define OHCI_ROOT_A_NPS (1 << 9) +#define OHCI_ROOT_A_PSM (1 << 8) + +/* + * Root hub B register masks + */ + +/* * Interrupt register masks */ #define OHCI_INTR_SO (1) @@ -334,10 +371,12 @@ struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */ }; -#define OHCI_TIMER -#define OHCI_TIMER_FREQ (1) /* frequency of OHCI status checks */ +#define OHCI_TIMER /* enable the OHCI timer */ +#define OHCI_TIMER_FREQ (234) /* ms between each root hub status check */ + +#undef OHCI_RHSC_INT /* Don't use root hub status interrupts! */ -/* Debugging code */ +/* Debugging code [ohci-debug.c] */ void show_ohci_ed(struct ohci_ed *ed); void show_ohci_td(struct ohci_td *td); void show_ohci_status(struct ohci *ohci); diff -ur --new-file old/linux/drivers/usb/uhci.c new/linux/drivers/usb/uhci.c --- old/linux/drivers/usb/uhci.c Fri Apr 30 17:20:53 1999 +++ new/linux/drivers/usb/uhci.c Sat May 15 03:36:17 1999 @@ -47,7 +47,7 @@ #define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0) -static struct wait_queue *uhci_configure = NULL; +static DECLARE_WAIT_QUEUE_HEAD(uhci_configure); /* * Return the result of a TD.. @@ -61,15 +61,17 @@ /* Some debugging code */ if (status) { int i = 10; - struct uhci_td *tmp = dev->control_td; + struct uhci_td *tmp = td->first; printk("uhci_td_result() failed with status %d\n", status); show_status(dev->uhci); do { show_td(tmp); - tmp++; + if ((tmp->link & 1) || (tmp->link & 2)) + break; + tmp = bus_to_virt(tmp->link & ~0xF); if (!--i) break; - } while (tmp <= td); + } while (1); } return status; } @@ -279,7 +281,7 @@ unsigned int destination, status; /* Destination: pipe destination with INPUT */ - destination = (pipe & 0x0007ff00) | 0x69; + destination = (pipe & 0x0007ff00) | 0x69; /* Status: slow/fast, Interrupt, Active, Short Packet Detect Infinite Errors */ status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23) | (1 << 29) | (0 << 27); @@ -292,6 +294,7 @@ td->status = status; /* In */ td->info = destination | (7 << 21); /* 8 bytes of data */ td->buffer = virt_to_bus(dev->data); + td->first = td; td->qh = interrupt_qh; interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh; @@ -305,6 +308,202 @@ } /* + * Isochronous thread operations + */ + +int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc) +{ + struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; + char *data = isodesc->data; + int i, totlen = 0; + + for (i = 0; i < isodesc->num; i++) { + char *cdata = bus_to_virt(isodesc->td[i].buffer & ~0xF); + int n = (isodesc->td[i].status + 1) & 0x7FF; + + if ((cdata != data) && (n)) + memmove(data, cdata, n); + +#if 0 +if (n && n != 960) + printk("underrun: %d %d\n", i, n); +#endif +if ((isodesc->td[i].status >> 16) & 0xFF) + printk("error: %d %X\n", i, (isodesc->td[i].status >> 16)); + + data += n; + totlen += n; + } + + return totlen; +} + +int uhci_unsched_isochronous(struct usb_device *usb_dev, void *_isodesc) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci *uhci = dev->uhci; + struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; + int i; + + if ((isodesc->frame < 0) || (isodesc->frame > 1023)) + return 1; + + /* Remove from previous frames */ + for (i = 0; i < isodesc->num; i++) { + /* Turn off Active and IOC bits */ + isodesc->td[i].status &= ~(3 << 23); + uhci->fl->frame[(isodesc->frame + i) % 1024] = isodesc->td[i].link; + } + + isodesc->frame = -1; + + return 0; +} + +/* td points to the one td we allocated for isochronous transfers */ +int uhci_sched_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci *uhci = dev->uhci; + struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; + struct uhci_iso_td *pisodesc = (struct uhci_iso_td *)_pisodesc; + int frame, i; + + if (isodesc->frame != -1) { + printk("isoc queue not removed\n"); + uhci_unsched_isochronous(usb_dev, isodesc); + } + + /* Insert TD into list */ + if (!pisodesc) { + frame = inw(uhci->io_addr + USBFRNUM) % 1024; + /* HACK: Start 2 frames from now */ + frame = (frame + 2) % 1024; + } else + frame = (pisodesc->endframe + 1) % 1024; + +#if 0 +printk("scheduling first at frame %d\n", frame); +#endif + + for (i = 0; i < isodesc->num; i++) { + /* Active */ + isodesc->td[i].status |= (1 << 23); + isodesc->td[i].backptr = &uhci->fl->frame[(frame + i) % 1024]; + isodesc->td[i].link = uhci->fl->frame[(frame + i) % 1024]; + uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(&isodesc->td[i]); + } + +#if 0 +printk("last at frame %d\n", (frame + i - 1) % 1024); +#endif + + /* Interrupt */ + isodesc->td[i - 1].status |= (1 << 24); + + isodesc->frame = frame; + isodesc->endframe = (frame + isodesc->num - 1) % 1024; + +#if 0 + return uhci_td_result(dev, td[num - 1]); +#endif + return 0; +} + +/* + * Initialize isochronous queue + */ +void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + unsigned long destination, status; + struct uhci_td *td; + struct uhci_iso_td *isodesc; + int i; + + isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL); + if (!isodesc) { + printk("Couldn't allocate isodesc!\n"); + return NULL; + } + memset(isodesc, 0, sizeof(*isodesc)); + + /* Carefully work around the non contiguous pages */ + isodesc->num = (len / PAGE_SIZE) * (PAGE_SIZE / maxsze); + isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL); + isodesc->frame = isodesc->endframe = -1; + isodesc->data = data; + isodesc->maxsze = maxsze; + + if (!isodesc->td) { + printk("Couldn't allocate td's\n"); + kfree(isodesc); + return NULL; + } + + isodesc->frame = isodesc->endframe = -1; + + /* + * Build the DATA TD's + */ + i = 0; + do { + /* Build the TD for control status */ + td = &isodesc->td[i]; + + /* The "pipe" thing contains the destination in bits 8--18 */ + destination = (pipe & 0x0007ff00); + + if (usb_pipeout(pipe)) + destination |= 0xE1; /* OUT */ + else + destination |= 0x69; /* IN */ + + /* Status: slow/fast, Active, Isochronous */ + status = (pipe & (1 << 26)) | (1 << 23) | (1 << 25); + + /* + * Build the TD for the control request + */ + td->status = status; + td->info = destination | ((maxsze - 1) << 21); + td->buffer = virt_to_bus(data); + td->first = td; + td->backptr = NULL; + + i++; + + data += maxsze; + + if (((int)data % PAGE_SIZE) + maxsze >= PAGE_SIZE) + data = (char *)(((int)data + maxsze) & ~(PAGE_SIZE - 1)); + + len -= maxsze; + } while (i < isodesc->num); + + /* IOC on the last TD */ + td->status |= (1 << 24); + uhci_add_irq_list(dev->uhci, td, completed, dev_id); + + return isodesc; +} + +void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc) +{ + struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; + + /* If it's still scheduled, unschedule them */ + if (isodesc->frame) + uhci_unsched_isochronous(usb_dev, isodesc); + + /* Remove it from the IRQ list */ + uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]); + + kfree(isodesc->td); + kfree(isodesc); +} + +/* * Control thread operations: we just mark the last TD * in a control thread as an interrupt TD, and wake up * the front-end on completion. @@ -312,7 +511,7 @@ * We need to remove the TD from the lists (both interrupt * list and TD lists) by hand if something bad happens! */ -static struct wait_queue *control_wakeup; +static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); static int uhci_control_completed(int status, void *buffer, void *dev_id) { @@ -323,7 +522,7 @@ /* td points to the last td in the list, which interrupts on completion */ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev); struct uhci_td *curtd; @@ -420,6 +619,7 @@ td->status = status; /* Try forever */ td->info = destination | (7 << 21); /* 8 bytes of data */ td->buffer = virt_to_bus(cmd); + td->first = td; /* * If direction is "send", change the frame from SETUP (0x2D) @@ -450,6 +650,7 @@ td->status = status; /* Status */ td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */ td->buffer = virt_to_bus(data); + td->first = first; td->backptr = &prevtd->link; prevtd = td; @@ -470,6 +671,7 @@ td->status = status | (1 << 24); /* IOC */ td->info = destination | (0x7ff << 21); /* 0 bytes of data */ td->buffer = 0; + td->first = first; td->backptr = &prevtd->link; /* Start it up.. */ @@ -498,6 +700,186 @@ return ret; } + +/* + * Bulk thread operations: we just mark the last TD + * in a bulk thread as an interrupt TD, and wake up + * the front-end on completion. + * + * We need to remove the TD from the lists (both interrupt + * list and TD lists) by hand if something bad happens! + */ +static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup); + +static int uhci_bulk_completed(int status, void *buffer, void *dev_id) +{ + wake_up(&bulk_wakeup); + return 0; /* Don't re-instate */ +} + +/* td points to the last td in the list, which interrupts on completion */ +static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last) +{ + DECLARE_WAITQUEUE(wait, current); + struct uhci_qh *bulk_qh = uhci_qh_allocate(dev); + struct uhci_td *curtd; + + + + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&bulk_wakeup, &wait); + + uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL); + + /* FIXME: This is kinda kludged */ + /* Walk the TD list and update the QH pointer */ + { + int maxcount = 100; + + curtd = first; + do { + curtd->qh = bulk_qh; + if (curtd->link & 1) + break; + + curtd = bus_to_virt(curtd->link & ~0xF); + if (!--maxcount) { + printk("runaway tds!\n"); + break; + } + } while (1); + } + + uhci_insert_tds_in_qh(bulk_qh, first, last); + +// bulk0 is empty here... +// show_status(dev->uhci); +// show_queues(dev->uhci); + + /* Add it into the skeleton */ + /*WARNING! HUB HAS NO BULK QH TIL NOW!!!!!!!!!!!*/ + uhci_insert_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh); + +// now we're in the queue... but don't ask WHAT is in there ;-( +// show_status(dev->uhci); +// show_queues(dev->uhci); + + schedule_timeout(HZ/10); + + remove_wait_queue(&bulk_wakeup, &wait); + + /* Clean up in case it failed.. */ + uhci_remove_irq_list(last); + +#if 0 + printk("Looking for tds [%p, %p]\n", dev->control_td, td); +#endif + + /* Remove it from the skeleton */ + uhci_remove_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh); + + uhci_qh_deallocate(bulk_qh); + + return uhci_td_result(dev, last); +} + +/* + * Send or receive a bulk message on a pipe. + * + * Note that the "pipe" structure is set up to map + * easily to the uhci destination fields. + * + * A bulk message is only built up from + * the data phase + * + * The data phase can be an arbitrary number of TD's + * although we currently had better not have more than + * 31 TD's here. + * + * 31 TD's is a minimum of 248 bytes worth of bulk + * information. + */ +static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_td *first, *td, *prevtd; + unsigned long destination, status; + int ret; + + if (len > usb_maxpacket(usb_dev->maxpacketsize) * 31) + printk("Warning, too much data for a bulk packet, crashing\n"); + + /* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */ + /* + IS THIS NECCESARY? PERHAPS WE CAN JUST USE THE PIPE + LOOK AT: usb_pipeout and the pipe bits + I FORGOT WHAT IT EXACTLY DOES + */ + if (usb_pipeout(pipe)) { + destination = (pipe & 0x0007ff00) | 0xE1; + } + else { + destination = (pipe & 0x0007ff00) | 0x69; + } + + /* Status: slow/fast, Active, Short Packet Detect Three Errors */ + status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); + + /* + * Build the TDs for the bulk request + */ + first = td = uhci_td_allocate(dev); + prevtd = first; //This is fake, but at least it's not NULL + while (len > 0) { + /* Build the TD for control status */ + int pktsze = len; + int maxsze = usb_maxpacket(pipe); + + if (pktsze > maxsze) + pktsze = maxsze; + + td->status = status; /* Status */ + td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */ + td->buffer = virt_to_bus(data); + td->backptr = &prevtd->link; + + prevtd = td; + td = uhci_td_allocate(dev); + prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */ + + data += maxsze; + len -= maxsze; + /* Alternate Data0/1 (start with Data0) */ + destination ^= 1 << 19; + } + td->link = 1; /* Terminate */ + + /* Start it up.. */ + ret = uhci_run_bulk(dev, first, td); + + { + int maxcount = 100; + struct uhci_td *curtd = first; + unsigned int nextlink; + + do { + nextlink = curtd->link; + uhci_remove_td(curtd); + uhci_td_deallocate(curtd); + if (nextlink & 1) /* Tail? */ + break; + + curtd = bus_to_virt(nextlink & ~0xF); + if (!--maxcount) { + printk("runaway td's!?\n"); + break; + } + } while (1); + } + + return ret; +} + static struct usb_device *uhci_usb_allocate(struct usb_device *parent) { struct usb_device *usb_dev; @@ -554,12 +936,16 @@ for (i = 0; i < UHCI_MAXTD; ++i) { struct uhci_td *td = dev->td + i; - /* And remove it from the irq list, if it's active */ - if (td->status & (1 << 23)) - uhci_remove_irq_list(td); - - if (td->inuse) + if (td->inuse) { uhci_remove_td(td); + + /* And remove it from the irq list, if it's active */ + if (td->status & (1 << 23)) + td->status &= ~(1 << 23); +#if 0 + uhci_remove_irq_list(td); +#endif + } } /* Remove the td from any queues */ @@ -581,6 +967,7 @@ uhci_usb_allocate, uhci_usb_deallocate, uhci_control_msg, + uhci_bulk_msg, uhci_request_irq, }; @@ -710,15 +1097,18 @@ __list_del(tmp->prev, next); INIT_LIST_HEAD(tmp); if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) { - struct uhci_qh *interrupt_qh = td->qh; - list_add(&td->irq_list, &uhci->interrupt_list); - td->info ^= 1 << 19; /* toggle between data0 and data1 */ - td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */ - /* Remove then readd? Is that necessary */ - uhci_remove_td(td); - uhci_insert_td_in_qh(interrupt_qh, td); + if (!(td->status & (1 << 25))) { + struct uhci_qh *interrupt_qh = td->qh; + + td->info ^= 1 << 19; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */ + + /* Remove then readd? Is that necessary */ + uhci_remove_td(td); + uhci_insert_td_in_qh(interrupt_qh, td); + } } /* If completed wants to not reactivate, then it's */ /* responsible for free'ing the TD's and QH's */ @@ -764,6 +1154,9 @@ status = inw(io_addr + USBSTS); outw(status, io_addr + USBSTS); + if ((status & ~0x21) != 0) + printk("interrupt: %X\n", status); + /* Walk the list of pending TD's to see which ones completed.. */ uhci_interrupt_notify(uhci); @@ -787,6 +1180,7 @@ td->status = (1 << 24); /* interrupt on completion */ td->info = (15 << 21) | 0x7f69; /* (ignored) input packet, 16 bytes, device 127 */ td->buffer = 0; + td->first = td; td->qh = NULL; uhci->fl->frame[0] = virt_to_bus(td); @@ -1047,11 +1441,12 @@ } } -#if 0 + { + int i; if(uhci->root_hub) for(i = 0; i < uhci->root_hub->usb->maxchild; i++) usb_disconnect(uhci->root_hub->usb->children + i); -#endif + } cleanup_drivers(); @@ -1185,29 +1580,10 @@ if (retval < 0) continue; -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif - hub_init(); -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif - return 0; } return retval; -} - -void cleanup_drivers(void) -{ - hub_cleanup(); -#ifdef CONFIG_USB_MOUSE - usb_mouse_cleanup(); -#endif } diff -ur --new-file old/linux/drivers/usb/uhci.h new/linux/drivers/usb/uhci.h --- old/linux/drivers/usb/uhci.h Wed Apr 28 20:14:03 1999 +++ new/linux/drivers/usb/uhci.h Sun May 16 22:19:01 1999 @@ -91,8 +91,20 @@ void *dev_id; int inuse; /* Inuse? */ struct uhci_qh *qh; + struct uhci_td *first; } __attribute__((aligned(32))); +struct uhci_iso_td { + int num; + char *data; + int maxsze; + + struct uhci_td *td; + + int frame; + int endframe; +}; + /* * Note the alignment requirements of the entries * @@ -102,7 +114,7 @@ */ struct uhci; -#define UHCI_MAXTD 64 +#define UHCI_MAXTD 64 #define UHCI_MAXQH 16 @@ -124,9 +136,11 @@ * The root hub pre-allocated QH's and TD's have * some special global uses.. */ +#if 0 #define control_td td /* Td's 0-30 */ /* This is only for the root hub's TD list */ #define tick_td td[31] +#endif /* * There are various standard queues. We set up several different @@ -224,6 +238,12 @@ void show_td(struct uhci_td * td); void show_status(struct uhci *uhci); void show_queues(struct uhci *uhci); + +int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc); +int uhci_unsched_isochronous(struct usb_device *usb_dev, void *_isodesc); +int uhci_sched_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc); +void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id); +void uhci_delete_isochronous(struct usb_device *dev, void *_isodesc); #endif diff -ur --new-file old/linux/drivers/usb/usb.c new/linux/drivers/usb/usb.c --- old/linux/drivers/usb/usb.c Sat May 8 00:16:04 1999 +++ new/linux/drivers/usb/usb.c Sat May 15 03:43:45 1999 @@ -42,6 +42,55 @@ #include "usb.h" +#ifdef CONFIG_USB_UHCI +int uhci_init(void); +#endif +#ifdef CONFIG_USB_OHCI +int ohci_init(void); +#endif +#ifdef CONFIG_USB_OHCI_HCD +int ohci_hcd_init(void); +#endif + +int usb_init(void) +{ +#ifdef CONFIG_USB_UHCI + uhci_init(); +#endif +#ifdef CONFIG_USB_OHCI + ohci_init(); +#endif +#ifdef CONFIG_USB_OHCI_HCD + ohci_hcd_init(); +#endif +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif +#ifdef CONFIG_USB_ACM + usb_acm_init(); +#endif +#ifdef CONFIG_USB_CPIA + usb_cpia_init(); +#endif + + usb_hub_init(); + return 0; +} + +void cleanup_drivers(void) +{ + hub_cleanup(); +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif +} + /* * We have a per-interface "registered driver" list. */ @@ -124,7 +173,7 @@ if (n_len < 2 || n_len > len) { - printk("Short descriptor.\n"); + printk("Short descriptor\n"); return -1; } printk( @@ -152,9 +201,12 @@ { int n_len = ptr[0]; + if (len <= 0) + return -1; + if (n_len < 2 || n_len > len) { - printk("Short descriptor.\n"); + printk("Short descriptor. (%d, %d)\n", len, n_len); return -1; } @@ -247,6 +299,11 @@ len -= *ptr; parsed += *ptr; + if (config->MaxPower == 200) { + printk("bNumInterfaces kludge\n"); + config->bNumInterfaces += 3; + } + if (config->bNumInterfaces > USB_MAXINTERFACES) { printk(KERN_WARNING "usb: too many interfaces.\n"); @@ -298,8 +355,10 @@ if (retval < 0) return retval; ptr += retval; - bytes += retval; + bytes -= retval; } + if (bytes) + printk(KERN_WARNING "usb: %d bytes of extra configuration data left\n", bytes); return 0; } @@ -534,6 +593,23 @@ return 0; } +int usb_set_interface(struct usb_device *dev, int interface, int alternate) +{ + devrequest dr; + + dr.requesttype = 1; + dr.request = USB_REQ_SET_INTERFACE; + dr.value = alternate; + dr.index = interface; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + + int usb_set_configuration(struct usb_device *dev, int configuration) { devrequest dr; @@ -569,20 +645,20 @@ int usb_get_configuration(struct usb_device *dev) { - unsigned int cfgno,size; + unsigned int cfgno; unsigned char buffer[400]; unsigned char * bufptr; - bufptr=buffer; - for (cfgno=0;cfgnodescriptor.bNumConfigurations;cfgno++) { + bufptr = buffer; + for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { + unsigned int size; /* Get the first 8 bytes - guaranteed */ if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) return -1; /* Get the full buffer */ size = *(unsigned short *)(bufptr+2); - if (bufptr+size > buffer+sizeof(buffer)) - { + if (bufptr+size > buffer+sizeof(buffer)) { printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); size = buffer+sizeof(buffer)-bufptr; } @@ -590,9 +666,9 @@ return -1; /* Prepare for next configuration */ - bufptr+=size; + bufptr += size; } - return usb_parse_configuration(dev, buffer, size); + return usb_parse_configuration(dev, buffer, bufptr - buffer); } /* diff -ur --new-file old/linux/drivers/usb/usb.h new/linux/drivers/usb/usb.h --- old/linux/drivers/usb/usb.h Tue May 11 19:04:03 1999 +++ new/linux/drivers/usb/usb.h Sun May 16 22:18:58 1999 @@ -6,6 +6,14 @@ #include #include +extern int usb_hub_init(void); +extern int usb_kbd_init(void); +extern int usb_cpia_init(void); +extern int usb_mouse_init(void); + +extern void hub_cleanup(void); +extern void usb_mouse_cleanup(void); + static __inline__ void wait_ms(unsigned int ms) { current->state = TASK_UNINTERRUPTIBLE; @@ -209,6 +217,7 @@ struct usb_device *(*allocate)(struct usb_device *); int (*deallocate)(struct usb_device *); int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int); + int (*bulk_msg)(struct usb_device *, unsigned int, void *, int); int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); }; @@ -262,6 +271,7 @@ extern void usb_device_descriptor(struct usb_device *dev); extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); +extern void usb_destroy_configuration(struct usb_device *dev); /* * Calling this entity a "pipe" is glorifying it. A USB pipe @@ -326,6 +336,8 @@ /* Create control pipes.. */ #define usb_sndctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint)) #define usb_rcvctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint) | 0x80) +#define usb_sndisocpipe(dev,endpoint) ((0 << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvisocpipe(dev,endpoint) ((0 << 30) | __create_pipe(dev,endpoint) | 0x80) #define usb_snddefctrl(dev) ((2 << 30) | __default_pipe(dev)) #define usb_rcvdefctrl(dev) ((2 << 30) | __default_pipe(dev) | 0x80) diff -ur --new-file old/linux/drivers/video/Config.in new/linux/drivers/video/Config.in --- old/linux/drivers/video/Config.in Wed May 12 01:30:36 1999 +++ new/linux/drivers/video/Config.in Fri May 14 08:48:20 1999 @@ -74,6 +74,7 @@ fi if [ "$ARCH" = "i386" ]; then bool 'VESA VGA graphics console' CONFIG_FB_VESA + bool 'VGA 16-color graphics console' CONFIG_FB_VGA16 define_bool CONFIG_VIDEO_SELECT y fi if [ "$CONFIG_VISWS" = "y" ]; then @@ -141,6 +142,7 @@ tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 # tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16 tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC + bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA else # Guess what we need @@ -282,6 +284,9 @@ if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then define_bool CONFIG_FBCON_MAC m fi + fi + if [ "$CONFIG_FB_VGA16" = "y" ]; then + define_bool CONFIG_FBCON_VGA_PLANES y fi if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then define_bool CONFIG_FBCON_VGA y diff -ur --new-file old/linux/drivers/video/Makefile new/linux/drivers/video/Makefile --- old/linux/drivers/video/Makefile Wed May 12 01:30:36 1999 +++ new/linux/drivers/video/Makefile Fri May 14 08:48:20 1999 @@ -202,6 +202,10 @@ L_OBJS += vesafb.o endif +ifeq ($(CONFIG_FB_VGA16),y) +L_OBJS += vga16fb.o +endif + ifeq ($(CONFIG_FB_VIRGE),y) L_OBJS += virgefb.o else @@ -459,6 +463,14 @@ else ifeq ($(CONFIG_FBCON_MFB),m) MX_OBJS += fbcon-mfb.o + endif +endif + +ifeq ($(CONFIG_FBCON_VGA_PLANES),y) +OX_OBJS += fbcon-vga-planes.o +else + ifeq ($(CONFIG_FBCON_VGA_PLANES),m) + MX_OBJS += fbcon-vga-planes.o endif endif diff -ur --new-file old/linux/drivers/video/fbcon-vga-planes.c new/linux/drivers/video/fbcon-vga-planes.c --- old/linux/drivers/video/fbcon-vga-planes.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/video/fbcon-vga-planes.c Fri May 14 08:48:20 1999 @@ -0,0 +1,364 @@ +/* + * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations + * for VGA 4-plane modes + * + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on code by Michael Schmitz + * Based on the old macfb.c 4bpp code by Alan Cox + * + * 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