From: Linus Torvalds Date: Fri, 23 Nov 2007 20:25:05 +0000 (-0500) Subject: Import 2.3.1 X-Git-Tag: 2.3.1 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=02ef408566a47da4d80a54c9e14acba77042bce0;p=history.git Import 2.3.1 --- diff --git a/CREDITS b/CREDITS index 52021ec29bcc..7b1b5f82669d 100644 --- a/CREDITS +++ b/CREDITS @@ -91,6 +91,11 @@ S: 20 Ames Street 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 @@ -765,6 +770,17 @@ N: Andrew Haylett 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 +944,10 @@ S: Na Orechovce 7 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 +958,13 @@ S: Dr. Holsts Vej 34, lejl. 164 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 @@ -1729,6 +1756,10 @@ E: hps@tanstaafl.de 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/ @@ -2015,6 +2046,9 @@ D: m68k/Amiga and PPC/CHRP Longtrail coordinator 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 --git a/Documentation/Configure.help b/Documentation/Configure.help index 3e09463a601e..c0c9e5bd92c7 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -289,9 +289,9 @@ CONFIG_BLK_DEV_NBD 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 @@ CONFIG_BLK_DEV_IDEDISK 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 @@ CONFIG_BLK_DEV_IDECD 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 @@ CONFIG_BLK_DEV_NS87415 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 @@ CMD646 chipset support (EXPERIMENTAL) 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 @@ CONFIG_BLK_DEV_ALI14XX 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 diff --git a/Documentation/devices.tex b/Documentation/devices.tex index 84c0e487507c..5bd758c0d6b1 100644 --- a/Documentation/devices.tex +++ b/Documentation/devices.tex @@ -254,7 +254,9 @@ Your cooperation is appreciated. \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} @@ -1745,6 +1747,16 @@ on {\url http://home.pages.de/~videotext/\/}. \minordots \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} @@ -1752,6 +1764,16 @@ on {\url http://home.pages.de/~videotext/\/}. \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)} \minor{0}{/dev/mtd0}{First MTD (rw)} diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 2d27f3644b95..92b2d621d6e7 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -1215,11 +1215,25 @@ Your cooperation is appreciated. 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) 1 = /dev/mtdr0 First MTD (ro) diff --git a/README b/README index b1bac81558f5..6c8b96d00cbc 100644 --- a/README +++ b/README @@ -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 @@ INSTALLING the kernel: - 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 @@ INSTALLING the kernel: 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 --git a/arch/i386/config.in b/arch/i386/config.in index 65a3aee0a71c..00c3b841bea9 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -168,7 +168,7 @@ endmenu source drivers/char/Config.in -# source drivers/usb/Config.in +source drivers/usb/Config.in source fs/Config.in diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 5bd7fe5bd0bd..bbf32f2bcd18 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -73,7 +73,9 @@ CONFIG_BLK_DEV_IDE=y # # 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_RZ1000=y 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_IDEDMA_AUTO=y # 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 # @@ -291,6 +295,17 @@ CONFIG_82C710_MOUSE=y # # 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 + # # Filesystems # diff --git a/arch/mips/lib/ide-no.c b/arch/mips/lib/ide-no.c index 5a11e03839c5..d2b4fe04a2f2 100644 --- a/arch/mips/lib/ide-no.c +++ b/arch/mips/lib/ide-no.c @@ -11,6 +11,7 @@ */ #include #include +#include #include #include @@ -24,8 +25,10 @@ static ide_ioreg_t no_ide_default_io_base(int index) 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 --git a/arch/mips/lib/ide-std.c b/arch/mips/lib/ide-std.c index e6bf4dc5f7f0..5b61daf46ec7 100644 --- a/arch/mips/lib/ide-std.c +++ b/arch/mips/lib/ide-std.c @@ -11,6 +11,7 @@ */ #include #include +#include #include static int std_ide_default_irq(ide_ioreg_t base) @@ -41,15 +42,23 @@ static ide_ioreg_t std_ide_default_io_base(int index) } } -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 --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index 55e57fc5b72c..2540e09111fc 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -561,9 +561,9 @@ apus_ide_fix_driveid(struct hd_driveid *id) } __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 --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 2c652f0498c1..99e97e69eae4 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -561,16 +562,23 @@ chrp_ide_fix_driveid(struct hd_driveid *id) 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; - - while (i--) - *p++ = port++; - *p++ = port; - if (irq != NULL) - *irq = chrp_ide_irq; + ide_ioreg_t reg = data_port; + int i; + + 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 --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c index 0f1eb3eb5f9c..f086ef743e84 100644 --- a/arch/ppc/kernel/mbx_setup.c +++ b/arch/ppc/kernel/mbx_setup.c @@ -380,23 +380,35 @@ mbx_ide_fix_driveid(struct hd_driveid *id) 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; - - while (i--) - *p++ = port++; - *p++ = base + 0x206; - if (irq != NULL) - *irq = 0; + ide_ioreg_t reg = data_port; + int i; + + *irq = 0; + + if (data_port != 0) /* Only map the first ATA flash drive */ + return; + #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 --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 9f8638021576..bfd34fea62d7 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -365,7 +365,7 @@ note_scsi_host(struct device_node *node, void *host)) #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 @@ pmac_ide_fix_driveid(struct hd_driveid *id) } /* 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 --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 834bdf102595..36a68ffd6762 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index de18f465adac..30207bf3d82c 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -691,14 +692,20 @@ prep_ide_fix_driveid(struct hd_driveid *id) } __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 --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c index 83333f660c25..dc740aaf6583 100644 --- a/arch/ppc/kernel/residual.c +++ b/arch/ppc/kernel/residual.c @@ -46,6 +46,7 @@ #include #include #include +#include #include diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 2d38f3adc98d..8e656d77ce0c 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -160,10 +161,10 @@ void machine_halt(void) } #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 --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index f0921ab9f3b9..c926f3a942e8 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -410,7 +410,11 @@ static int report_statvfs(struct inode *inode, u32 buf) 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 @@ static int report_statvfs64(struct inode *inode, u32 buf) 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 @@ asmlinkage int solaris_statvfs(u32 path, u32 buf) 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 @@ asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf) 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 @@ asmlinkage int solaris_statvfs64(u32 path, u32 buf) 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 @@ asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf) 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 --git a/drivers/block/Config.in b/drivers/block/Config.in index 390aa708ce30..47fc9eac1b79 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -19,7 +19,13 @@ if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then 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 @@ else 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 @@ else 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 @@ -129,6 +163,19 @@ 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 define_bool CONFIG_BLK_DEV_HD y else diff --git a/drivers/block/MAKEDEV-IDE45 b/drivers/block/MAKEDEV-IDE45 new file mode 100644 index 000000000000..c55a9b3cf1c2 --- /dev/null +++ b/drivers/block/MAKEDEV-IDE45 @@ -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 --git a/drivers/block/MAKEDEV-IDE67 b/drivers/block/MAKEDEV-IDE67 new file mode 100644 index 000000000000..27728be28e65 --- /dev/null +++ b/drivers/block/MAKEDEV-IDE67 @@ -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 --git a/drivers/block/Makefile b/drivers/block/Makefile index 79f3a9547fd1..fd9b99c35493 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -158,6 +158,22 @@ ifeq ($(CONFIG_BLK_DEV_VIA82C586),y) 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 @@ -166,6 +182,30 @@ 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 ifeq ($(CONFIG_PROC_FS),y) diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c new file mode 100644 index 000000000000..c00cac8823e8 --- /dev/null +++ b/drivers/block/aec6210.c @@ -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 --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index 5d5ca66dc79d..46a275305122 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -47,8 +47,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* port addresses for auto-detection */ diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c new file mode 100644 index 000000000000..013b4724a628 --- /dev/null +++ b/drivers/block/alim15x3.c @@ -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 --git a/drivers/block/buddha.c b/drivers/block/buddha.c new file mode 100644 index 000000000000..8086dac560eb --- /dev/null +++ b/drivers/block/buddha.c @@ -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 --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index 9982493701c1..ee6d7c9cc96b 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -110,8 +110,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff --git a/drivers/block/cmd646.c b/drivers/block/cmd646.c index 57b5931319ff..de0844a874cc 100644 --- a/drivers/block/cmd646.c +++ b/drivers/block/cmd646.c @@ -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 @@ static int cmd646_config_drive_for_dma(ide_drive_t *drive) } /* 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 @@ static int cmd646_dmaproc(ide_dma_action_t func, ide_drive_t *drive) 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 @@ __initfunc(void ide_init_cmd646 (ide_hwif_t *hwif)) (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 --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c new file mode 100644 index 000000000000..59c38beea4ef --- /dev/null +++ b/drivers/block/cy82c693.c @@ -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 --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index b656a0bd27c3..d805dec759d5 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -14,8 +14,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff --git a/drivers/block/falconide.c b/drivers/block/falconide.c new file mode 100644 index 000000000000..321569eb15ba --- /dev/null +++ b/drivers/block/falconide.c @@ -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 --git a/drivers/block/gayle.c b/drivers/block/gayle.c new file mode 100644 index 000000000000..920f2ee0adba --- /dev/null +++ b/drivers/block/gayle.c @@ -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 --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 3169a9bfda72..761a3eb0c885 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -83,6 +83,10 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) * 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: diff --git a/drivers/block/hpt343.c b/drivers/block/hpt343.c new file mode 100644 index 000000000000..820e9057d464 --- /dev/null +++ b/drivers/block/hpt343.c @@ -0,0 +1,394 @@ +/* + * 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 + + pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x80); + 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 --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c index a3e1229bca65..d9fb885c278c 100644 --- a/drivers/block/ht6560b.c +++ b/drivers/block/ht6560b.c @@ -57,8 +57,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 7e07eda65966..c1d050c46f48 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -258,13 +258,14 @@ #include #include #include +#include + #include #include #include #include #include -#include "ide.h" #include "ide-cd.h" /**************************************************************************** @@ -670,7 +671,8 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, 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 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) 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 @@ static void ide_cdrom_add_settings(ide_drive_t *drive) 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 --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 14ad6269ec2f..955be4c6b182 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -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 @@ static int lba_capacity_is_ok (struct hd_driveid *id) 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 */ @@ -220,6 +232,9 @@ void ide_multwrite (ide_drive_t *drive, unsigned int mcount) printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n", 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; @@ -279,7 +294,11 @@ static void set_multmode_intr (ide_drive_t *drive) { 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 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl 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 @@ static void idedisk_setup (ide_drive_t *drive) 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 @@ static void idedisk_setup (ide_drive_t *drive) 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 --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 17f46f464f85..9f26ea6bc5b9 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -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 *good_dma_drives[] = {"Micropolis 2112A", */ 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 @@ void ide_dma_intr (ide_drive_t *drive) * 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 @@ int ide_build_dmatable (ide_drive_t *drive) * 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 @@ int ide_build_dmatable (ide_drive_t *drive) 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 @@ int ide_build_dmatable (ide_drive_t *drive) } } } 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 ide_build_dmatable (ide_drive_t *drive) */ 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 @@ int check_drive_lists (ide_drive_t *drive, int good_bad) } } } +#endif /* IDE_DMA_NEW_LISTINGS */ return 0; } @@ -269,18 +357,24 @@ static int config_drive_for_dma (ide_drive_t *drive) 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 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) 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 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) 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 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c 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 --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index 30c862f11ed3..78aa7fe29967 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -52,11 +53,6 @@ #include #include -/* - * Main Linux ide driver include file - */ -#include "ide.h" - /* * The following are used to debug the driver. */ @@ -1011,7 +1007,8 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) 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 --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index df9c715e1d17..cc6a3462bc6b 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -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 @@ extern void ide_init_rz1000(ide_hwif_t *); #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_enablebit_s { 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,28 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { __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); + pci_write_config_byte(dev, 0x80, 0x80); + 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 +344,7 @@ __initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *n */ 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 +400,13 @@ check_if_enabled: 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 +421,19 @@ check_if_enabled: 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 +457,8 @@ check_if_enabled: 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 +476,10 @@ check_if_enabled: } } 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 +487,12 @@ check_if_enabled: 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 +506,18 @@ check_if_enabled: 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 +547,8 @@ __initfunc(void ide_scan_pcibus (void)) 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 --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index d8d353d876c1..1156d368935d 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -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 @@ struct notifier_block idepmac_sleep_notifier = { * 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 @@ void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) } } -__initfunc(void -pmac_ide_probe(void)) +__initfunc(void pmac_ide_probe(void)) { struct device_node *np; int i; @@ -172,7 +181,8 @@ pmac_ide_probe(void)) 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 --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 1d13043e8a76..bc3954b7dd3f 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -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; @@ -147,17 +149,6 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) return; } -/* - * 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 @@ -176,20 +167,26 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) 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 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) (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 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) __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 @@ static int do_probe (ide_drive_t *drive, byte cmd) (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 @@ static int do_probe (ide_drive_t *drive, byte cmd) 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 @@ static int do_probe (ide_drive_t *drive, byte cmd) } 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 @@ static void probe_hwif (ide_hwif_t *hwif) 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 @@ static void probe_hwif (ide_hwif_t *hwif) 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 @@ static void init_gendisk (ide_hwif_t *hwif) 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 @@ static int hwif_init (ide_hwif_t *hwif) 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 @@ static int hwif_init (ide_hwif_t *hwif) #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 --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index 26a56e740690..f985980b1216 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -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 @@ void proc_ide_create(void) 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 @@ void proc_ide_destroy(void) * 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 --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index e97087097dc1..1382eb3abf54 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -338,6 +338,8 @@ #include #include #include +#include +#include #include #include @@ -346,11 +348,6 @@ #include #include -/* - * Main Linux ide driver include file - */ -#include "ide.h" - /* * For general magnetic tape device compatibility. */ @@ -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 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) 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); @@ -3337,16 +3342,16 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) 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 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) } 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 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) 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 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) 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 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) 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 --git a/drivers/block/ide.c b/drivers/block/ide.c index e93a7d454223..6b59faed30b1 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -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 */ @@ -117,6 +125,7 @@ #include #include #include +#include #include #include @@ -124,24 +133,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 +201,18 @@ static inline void set_recovery_timer (ide_hwif_t *hwif) 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 +229,7 @@ static void init_hwif_data (unsigned int index) 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 +238,7 @@ static void init_hwif_data (unsigned int index) drive->name[0] = 'h'; drive->name[1] = 'd'; drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; + init_waitqueue_head(&drive->wqueue); } } @@ -246,9 +266,13 @@ static void init_ide_data (void) 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 +676,10 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) 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 +885,8 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) 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 +1282,20 @@ void do_ide5_request (void) } #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 +1413,12 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) __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 +1440,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) * 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 +1451,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) 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) @@ -1753,7 +1800,8 @@ void ide_unregister (unsigned int index) * 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 +1865,58 @@ abort: 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 +1928,33 @@ found: 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 +2179,24 @@ int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int secto 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; @@ -2166,7 +2284,68 @@ static int ide_ioctl (struct inode *inode, struct file *file, 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) @@ -2251,6 +2430,32 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap) *p++ = '\0'; } +/* + * + */ +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 +2575,22 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i * "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 +2600,7 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i * "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 +2612,17 @@ __initfunc(void ide_setup (char *s)) 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 +2686,58 @@ __initfunc(void ide_setup (char *s)) } } +#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 +2771,9 @@ __initfunc(void ide_setup (char *s)) 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 +2877,9 @@ __initfunc(void ide_setup (char *s)) 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 +2916,122 @@ done: * an IDE disk drive, or if a geometry was "forced" on the commandline. * Returns 1 if the geometry translation was successful. */ + +#define ANDRIES_GEOMETRY 0 + int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) { ide_drive_t *drive; + +#if ANDRIES_GEOMETRY + /* + * This is the documented list of values (some version of) + * OnTrack DM uses. + */ + + static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; + + /* + * This is a pure phantasy list - known to be incorrect. + * + * In fact it seems that EZD does not do anything to the CHS + * values in the partition table, so whether EZD is present + * or not should probably not influence the geometry. + */ + + static const byte ez_head_vals[] = {4, 8, 16, 32, 64, 128, 240, 255, 0}; const byte *heads; + unsigned long tracks; + + drive = get_info_ptr(i_rdev); + if (!drive) + return 0; + + if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) { + /* + * 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; + return 0; /* we already have a translation */ + } + + if (xparm == -1) { + int ret = 0; +#if FAKE_FDISK_FOR_EZDRIVE + if (drive->remap_0_to_1 == 0) { + drive->remap_0_to_1 = 1; + printk("%s [remap 0->1]", msg); + msg = NULL; + ret = 1; + } + if (drive->bios_head > 16) +#endif /* FAKE_FDISK_FOR_EZDRIVE */ + { + /* + * 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; + return ret; /* we already have a translation */ + } + } + + if (msg) + printk("%s ", msg); + + if (drive->forced_geom) { + /* + * 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; + return 0; + } + +#if 1 + /* There used to be code here that assigned drive->id->CHS + to drive->CHS and that to drive->bios_CHS. However, + some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB. + In such cases that code was wrong. Moreover, + there seems to be no reason to do any of these things. */ +#else + if (drive->id) { + drive->cyl = drive->id->cyls; + drive->head = drive->id->heads; + drive->sect = drive->id->sectors; + } + drive->bios_cyl = drive->cyl; + drive->bios_head = drive->head; + drive->bios_sect = drive->sect; + drive->special.b.set_geometry = 1; + +#endif + + tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63; + drive->bios_sect = 63; + if (xparm > 1) { + drive->bios_head = xparm; + drive->bios_cyl = tracks / drive->bios_head; + } else { + heads = (xparm == -1) ? ez_head_vals : dm_head_vals; + while (drive->bios_cyl >= 1024) { + drive->bios_head = *heads; + drive->bios_cyl = tracks / drive->bios_head; + if (0 == *++heads) + break; + } + if (xparm == 1) { + drive->sect0 = 63; + drive->bios_cyl = (tracks - 1) / drive->bios_head; + printk("[remap +63] "); + } + } + +#else /* ANDRIES_GEOMETRY */ + static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; const byte *heads = head_vals; unsigned long tracks; @@ -2708,14 +3106,16 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) printk("[remap +63] "); } } +#endif /* ANDRIES_GEOMETRY */ + 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 +3158,42 @@ __initfunc(static void probe_for_hwifs (void)) 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 +3468,12 @@ EXPORT_SYMBOL(do_ide4_request); #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 +3498,7 @@ EXPORT_SYMBOL(ide_end_request); 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 +3508,23 @@ EXPORT_SYMBOL(proc_ide_read_geometry); 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 --git a/drivers/block/ide.h b/drivers/block/ide.h deleted file mode 100644 index 52bb4e258d39..000000000000 --- a/drivers/block/ide.h +++ /dev/null @@ -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 *) */ - wait_queue_head_t 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 --git a/drivers/block/ide_modes.h b/drivers/block/ide_modes.h index 49a4997e38bc..d8c8a7144320 100644 --- a/drivers/block/ide_modes.h +++ b/drivers/block/ide_modes.h @@ -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 @@ static struct ide_pio_info { { "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 @@ byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, } #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 --git a/drivers/block/macide.c b/drivers/block/macide.c new file mode 100644 index 000000000000..2771ea702414 --- /dev/null +++ b/drivers/block/macide.c @@ -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 --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c index 3275c017132d..439e288a1672 100644 --- a/drivers/block/ns87415.c +++ b/drivers/block/ns87415.c @@ -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 --git a/drivers/block/opti621.c b/drivers/block/opti621.c index bc2cf8949d4b..0885ed49e539 100644 --- a/drivers/block/opti621.c +++ b/drivers/block/opti621.c @@ -98,8 +98,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" #define OPTI621_MAX_PIO 3 diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c new file mode 100644 index 000000000000..cbd8365bb03f --- /dev/null +++ b/drivers/block/pdc202xx.c @@ -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 --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index e032da579f57..5c05b1bd07de 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -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 @@ int init_pdc4030 (void) { 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; + 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; + 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 @@ int init_pdc4030 (void) 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 @@ int init_pdc4030 (void) 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 @@ static void promise_read_intr (ide_drive_t *drive) 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 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) 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 --git a/drivers/block/piix.c b/drivers/block/piix.c new file mode 100644 index 000000000000..d6efc89a1d40 --- /dev/null +++ b/drivers/block/piix.c @@ -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 --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index 9c1d0ed71317..d7b2784d1985 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -19,8 +19,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c index fe8c229004db..ae8749813248 100644 --- a/drivers/block/rz1000.c +++ b/drivers/block/rz1000.c @@ -26,9 +26,10 @@ #include #include #include -#include #include -#include "ide.h" +#include + +#include #ifdef CONFIG_BLK_DEV_IDEPCI diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 7fca7d5d9777..2f08740eadfe 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -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 --git a/drivers/block/trm290.c b/drivers/block/trm290.c index a502fedf6798..c4f96d49206b 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -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 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) 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 --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c index 77121ca3e017..13f5f39a7f55 100644 --- a/drivers/block/umc8672.c +++ b/drivers/block/umc8672.c @@ -47,8 +47,10 @@ #include #include #include +#include + #include -#include "ide.h" + #include "ide_modes.h" /* diff --git a/drivers/block/via82c586.c b/drivers/block/via82c586.c index 28bf80c76284..40720edbd300 100644 --- a/drivers/block/via82c586.c +++ b/drivers/block/via82c586.c @@ -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 --git a/drivers/char/serial.c b/drivers/char/serial.c index e8c1effd6ba2..7a3d4b5bcb88 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -2571,6 +2571,9 @@ static int get_async_struct(int line, struct async_struct **ret_info) 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 --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 92e2ee544963..9f32ec5e67dc 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -741,7 +741,6 @@ isdn_status_callback(isdn_ctrl * c) 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 @@ isdn_getnum(char **p) * 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 @@ register_isdn(isdn_if * i) 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 @@ register_isdn(isdn_if * i) 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 @@ register_isdn(isdn_if * i) 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 @@ isdn_init(void) 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 --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h index 6cb503b9f566..a8513fe5018c 100644 --- a/drivers/isdn/isdn_common.h +++ b/drivers/isdn/isdn_common.h @@ -90,7 +90,7 @@ extern char *isdn_map_eaz2msn(char *msn, int di); 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 --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 5da3a49f034b..aaaac3fdc7fa 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -359,8 +359,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp) 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 @@ isdn_ppp_closewait(int slot) 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 @@ isdn_ppp_open(int min, struct file *file) 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 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) 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 @@ isdn_ppp_init(void) 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 --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index a37178676938..1c77c6c009f6 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1567,8 +1567,7 @@ isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) 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 @@ isdn_tty_modem_init(void) 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 --git a/drivers/pci/oldproc.c b/drivers/pci/oldproc.c index da516f09ee6c..c845c33c2600 100644 --- a/drivers/pci/oldproc.c +++ b/drivers/pci/oldproc.c @@ -203,6 +203,7 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 632e3d08a5a8..cb1d9f0883b3 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -11,20 +11,18 @@ 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 - - bool 'USB mouse support' CONFIG_USB_MOUSE - bool 'USB keyboard support' CONFIG_USB_KBD - bool 'USB audio parsing support' CONFIG_USB_AUDIO +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 + + bool 'USB mouse support' CONFIG_USB_MOUSE + bool 'USB keyboard support' CONFIG_USB_KBD + bool 'USB audio parsing support' CONFIG_USB_AUDIO fi endmenu diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 6c6e7b091cc0..bc40725d3460 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -32,6 +32,10 @@ ifeq ($(CONFIG_USB_AUDIO),y) USBX_OBJS += audio.o endif +ifeq ($(CONFIG_USB_CPIA),y) + USBX_OBJS += cpia.o +endif + ifeq ($(CONFIG_USB), y) L_OBJS += $(USBX_OBJS) endif diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c new file mode 100644 index 000000000000..004ea4e7bbc4 --- /dev/null +++ b/drivers/usb/cpia.c @@ -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 cpia_init(void) +{ + usb_register(&cpia_driver); + + return 0; +} + diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h new file mode 100644 index 000000000000..51ff43e79404 --- /dev/null +++ b/drivers/usb/cpia.h @@ -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 --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c index 59b93bd82f6c..1e98f5e8d42a 100644 --- a/drivers/usb/mouse.c +++ b/drivers/usb/mouse.c @@ -54,11 +54,7 @@ struct mouse_state { /* but we will also need a list of file pointers to identify it */ }; -static struct mouse_state static_mouse_state = { - 0, 0, 0, 0, - 0, 0, 0, - __WAIT_QUEUE_HEAD_INITIALIZER(static_mouse_state.wait), -}; +static struct mouse_state static_mouse_state; spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; @@ -281,7 +277,7 @@ int usb_mouse_init(void) 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 --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index c9a57627aa21..f0fb1332d9da 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -61,15 +61,17 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td) /* 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 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d 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 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d 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; @@ -304,6 +307,202 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d return 0; } +/* + * 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; + int ret, i; + struct uhci_iso_td *isodesc; + + 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 @@ -420,6 +619,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void 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 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void 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 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void 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.. */ @@ -554,12 +756,16 @@ static int uhci_usb_deallocate(struct usb_device *usb_dev) 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 */ @@ -710,15 +916,18 @@ static void uhci_interrupt_notify(struct uhci *uhci) __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 +973,9 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) 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 +999,7 @@ static void uhci_init_ticktd(struct uhci *uhci) 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 +1260,12 @@ static int uhci_control_thread(void * __uhci) } } -#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(); @@ -1195,6 +1409,9 @@ int uhci_init(void) #ifdef CONFIG_USB_AUDIO usb_audio_init(); #endif +#ifdef CONFIG_USB_CPIA + cpia_init(); +#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h index f063356acc58..3f511eedb5af 100644 --- a/drivers/usb/uhci.h +++ b/drivers/usb/uhci.h @@ -91,8 +91,20 @@ struct uhci_td { 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_td { */ struct uhci; -#define UHCI_MAXTD 64 +#define UHCI_MAXTD 64 #define UHCI_MAXQH 16 @@ -124,9 +136,11 @@ struct uhci_device { * 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 @@ -225,5 +239,11 @@ 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 --git a/drivers/usb/usb.c b/drivers/usb/usb.c index f5e89ea8986c..2040c69ba96a 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -124,7 +124,7 @@ static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desc if (n_len < 2 || n_len > len) { - printk("Short descriptor.\n"); + printk("Short descriptor\n"); return -1; } printk( @@ -152,9 +152,12 @@ static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desct { 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 +250,11 @@ static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor 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 +306,10 @@ int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes) 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 +544,23 @@ int usb_set_idle(struct usb_device *dev, int duration, int report_id) 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; diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index 10379ef88da4..903e4d852d10 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -326,6 +326,8 @@ static inline unsigned int __default_pipe(struct usb_device *dev) /* 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 --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 7c2d2259f6c5..738bb40b896a 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -138,9 +138,6 @@ int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp) struct super_block *sb; int i, size; - if (!inode) - return 0; - sb = inode->i_sb; size = 2048 >> sb->s_blocksize_bits; diff --git a/fs/adfs/namei.c b/fs/adfs/namei.c index df3b5e457add..4e41c0975c17 100644 --- a/fs/adfs/namei.c +++ b/fs/adfs/namei.c @@ -46,9 +46,6 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name unsigned long parent_object_id, dir_object_id; int buffers, pos; - if (!S_ISDIR(dir->i_mode)) - return 0; - sb = dir->i_sb; if (adfs_inode_validate (dir)) { @@ -57,9 +54,6 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name return 0; } - if (namelen > ADFS_NAME_LEN) - return 0; - if (!(buffers = adfs_dir_read (dir, bh))) { adfs_error (sb, "adfs_find_entry", "unable to read directory"); return 0; diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c index d6944e889d4f..425df6577342 100644 --- a/fs/autofs/dir.c +++ b/fs/autofs/dir.c @@ -16,8 +16,6 @@ static int autofs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *inode=filp->f_dentry->d_inode; - if (!inode || !S_ISDIR(inode->i_mode)) - return -ENOTDIR; switch((unsigned long) filp->f_pos) { diff --git a/fs/autofs/root.c b/fs/autofs/root.c index c0caee9df565..c1b57ec6e969 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -72,9 +72,6 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi struct inode * inode = filp->f_dentry->d_inode; off_t onr, nr; - if (!inode || !S_ISDIR(inode->i_mode)) - return -ENOTDIR; - sbi = autofs_sbi(inode->i_sb); dirhash = &sbi->dirhash; nr = filp->f_pos; diff --git a/fs/buffer.c b/fs/buffer.c index 2fe2f199b55d..831bcdf206d3 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -100,8 +100,7 @@ union bdflush_param{ each time we call refill */ int nref_dirt; /* Dirty buffer threshold for activating bdflush when trying to refill buffers. */ - int interval; /* Interval (seconds) between spontaneous - bdflush runs */ + int dummy1; /* unused */ int age_buffer; /* Time for normal buffer to age before we flush it */ int age_super; /* Time for superblock to age before we @@ -110,10 +109,10 @@ union bdflush_param{ int dummy3; /* unused */ } b_un; unsigned int data[N_PARAM]; -} bdf_prm = {{40, 2000, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}}; +} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}}; /* These are the min and max parameter values that we will allow to be assigned */ -int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 1, 1*HZ, 1*HZ, 1, 1}; +int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 1*HZ, 1, 1}; int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5}; void wakeup_bdflush(int); @@ -1556,14 +1555,15 @@ void __init buffer_init(unsigned long memory_size) * response to dirty buffers. Once this process is activated, we write back * a limited number of buffers to the disks and then go back to sleep again. */ +static DECLARE_WAIT_QUEUE_HEAD(bdflush_wait); static DECLARE_WAIT_QUEUE_HEAD(bdflush_done); struct task_struct *bdflush_tsk = 0; void wakeup_bdflush(int wait) { - if (current == bdflush_tsk || !bdflush_tsk) + if (current == bdflush_tsk) return; - wake_up_process(bdflush_tsk); + wake_up(&bdflush_wait); if (wait) { run_task_queue(&tq_disk); sleep_on(&bdflush_done); @@ -1572,107 +1572,82 @@ void wakeup_bdflush(int wait) /* - * Here we attempt to write back old buffers. - * To prevent deadlocks for a loop device: - * 1) Do non-blocking writes to loop (avoids deadlock with running - * out of request blocks). - * 2) But do a blocking write if the only dirty buffers are loop buffers - * (otherwise we go into an infinite busy-loop). - * 3) Quit writing loop blocks if a freelist went low (avoids deadlock - * with running out of free buffers for loop's "real" device). -*/ + * Here we attempt to write back old buffers. We also try to flush inodes + * and supers as well, since this function is essentially "update", and + * otherwise there would be no way of ensuring that these quantities ever + * get written back. Ideally, we would have a timestamp on the inodes + * and superblocks so that we could write back only the old ones as well + */ -static inline void sync_old_buffers(void) +static int sync_old_buffers(void) { int i; - int ndirty = 0; - int wrta_cmd = WRITEA; -#ifdef DEBUG - int ncount = 0, nwritten = 0; -#endif + int ndirty, nwritten; + int nlist; + int ncount; struct buffer_head * bh, *next; -#ifdef DEBUG - bh = lru_list[BUF_CLEAN]; - if(bh) - for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) { - next = bh->b_next_free; + sync_supers(0); + sync_inodes(0); - /* Dirty/locked buffer on clean list? Refile it */ - if (buffer_locked(bh) || buffer_dirty(bh)) { - ncount++; - refile_buffer(bh); - } - } + ncount = 0; +#ifdef DEBUG + for(nlist = 0; nlist < NR_LIST; nlist++) +#else + for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) #endif + { + ndirty = 0; + nwritten = 0; + repeat: - bh = lru_list[BUF_LOCKED]; - if(bh) - for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) { - next = bh->b_next_free; - - /* Unlocked buffer on locked list? Refile it */ - if (!buffer_locked(bh)) - refile_buffer(bh); - } - - restart: - bh = lru_list[BUF_DIRTY]; - if(bh) - for (i = nr_buffers_type[BUF_DIRTY]; - i-- > 0 && ndirty < bdf_prm.b_un.ndirty; - bh = next) { - /* We may have stalled while waiting for - I/O to complete. */ - if(bh->b_list != BUF_DIRTY) - goto restart; - next = bh->b_next_free; - if(!lru_list[BUF_DIRTY]) { - printk("Dirty list empty %d\n", i); - break; - } - - /* Clean buffer on dirty list? Refile it */ - if (!buffer_dirty(bh)) { - refile_buffer(bh); - continue; - } - - if (buffer_locked(bh)) - continue; - /* Should we write back buffers that are - shared or not?? Currently dirty buffers - are not shared, so it does not matter */ - next->b_count++; - bh->b_count++; - ndirty++; - bh->b_flushtime = 0; - if (MAJOR(bh->b_dev) == LOOP_MAJOR) { - ll_rw_block(wrta_cmd,1, &bh); - wrta_cmd = WRITEA; - if (buffer_dirty(bh)) - --ndirty; - } - else - ll_rw_block(WRITE, 1, &bh); - bh->b_count--; - next->b_count--; - } - /* If we didn't write anything, but there are still - * dirty buffers, then make the next write to a - * loop device to be a blocking write. - * This lets us block--which we _must_ do! */ - if (ndirty == 0 - && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) { - wrta_cmd = WRITE; - goto restart; + bh = lru_list[nlist]; + if(bh) + for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) { + /* We may have stalled while waiting for I/O to complete. */ + if(bh->b_list != nlist) goto repeat; + next = bh->b_next_free; + if(!lru_list[nlist]) { + printk("Dirty list empty %d\n", i); + break; + } + + /* Clean buffer on dirty list? Refile it */ + if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) { + refile_buffer(bh); + continue; + } + + /* Unlocked buffer on locked list? Refile it */ + if (nlist == BUF_LOCKED && !buffer_locked(bh)) { + refile_buffer(bh); + continue; + } + + if (buffer_locked(bh) || !buffer_dirty(bh)) + continue; + ndirty++; + if(time_before(jiffies, bh->b_flushtime)) + continue; + nwritten++; + next->b_count++; + bh->b_count++; + bh->b_flushtime = 0; +#ifdef DEBUG + if(nlist != BUF_DIRTY) ncount++; +#endif + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + next->b_count--; + } } - + run_task_queue(&tq_disk); #ifdef DEBUG if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount); - printk("wrote %d/%d buffers...", nwritten, ndirty); + printk("Wrote %d/%d buffers\n", nwritten, ndirty); #endif run_task_queue(&tq_disk); + return 0; } @@ -1689,12 +1664,10 @@ asmlinkage int sys_bdflush(int func, long data) if (!capable(CAP_SYS_ADMIN)) goto out; - if (func == 1) - /* Func 1 used to call sync_old_buffers; a user space - daemon would call it periodically. This is no - longer necessary. Returning -EPERM here makes the - daemon silently exit. */ - goto out; + if (func == 1) { + error = sync_old_buffers(); + goto out; + } /* Basically func 1 means read param 1, 2 means write param 1, etc */ if (func >= 2) { @@ -1723,17 +1696,27 @@ out: return error; } -/* This is the actual bdflush daemon itself. It used to be started - * from the syscall above, but now we launch it ourselves internally - * with kernel_thread(...) directly after the first thread in - * init/main.c. Every so often, or when woken up by another task that - * needs memory, we call sync_old_buffers to partially clear the dirty list. - */ +/* This is the actual bdflush daemon itself. It used to be started from + * the syscall above, but now we launch it ourselves internally with + * kernel_thread(...) directly after the first thread in init/main.c */ +/* To prevent deadlocks for a loop device: + * 1) Do non-blocking writes to loop (avoids deadlock with running + * out of request blocks). + * 2) But do a blocking write if the only dirty buffers are loop buffers + * (otherwise we go into an infinite busy-loop). + * 3) Quit writing loop blocks if a freelist went low (avoids deadlock + * with running out of free buffers for loop's "real" device). +*/ int bdflush(void * unused) { - long remaining = HZ * bdf_prm.b_un.interval; - struct task_struct *tsk = current; + int i; + int ndirty; + int nlist; + int ncount; + struct buffer_head * bh, *next; + int major; + int wrta_cmd = WRITEA; /* non-blocking write for LOOP */ /* * We have a bare-bones task_struct, and really should fill @@ -1741,12 +1724,10 @@ int bdflush(void * unused) * display semi-sane things. Not real crucial though... */ - tsk->session = 1; - tsk->pgrp = 1; - tsk->dumpable = 0; /* inhibit ptrace() */ - strcpy(tsk->comm, "kflushd"); - sigfillset(&tsk->blocked); - bdflush_tsk = tsk; + current->session = 1; + current->pgrp = 1; + sprintf(current->comm, "kflushd"); + bdflush_tsk = current; /* * As a kernel thread we want to tamper with system buffers @@ -1756,36 +1737,93 @@ int bdflush(void * unused) lock_kernel(); for (;;) { - tsk->state = TASK_INTERRUPTIBLE; - remaining = schedule_timeout(remaining); - #ifdef DEBUG printk("bdflush() activated..."); #endif - CHECK_EMERGENCY_SYNC - if (remaining == 0) { - /* - * Also try to flush inodes and supers, since - * otherwise there would be no way of ensuring - * that these quantities ever get written - * back. Ideally, we would have a timestamp - * on the inodes and superblocks so that we - * could write back only the old ones. - */ - sync_supers(0); - sync_inodes(0); - remaining = HZ * bdf_prm.b_un.interval; - } - - /* Keep flushing till there aren't very many dirty buffers */ - do { - sync_old_buffers(); - } while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100); + CHECK_EMERGENCY_SYNC - wake_up(&bdflush_done); + ncount = 0; #ifdef DEBUG + for(nlist = 0; nlist < NR_LIST; nlist++) +#else + for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) +#endif + { + ndirty = 0; + repeat: + + bh = lru_list[nlist]; + if(bh) + for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; + bh = next) { + /* We may have stalled while waiting for I/O to complete. */ + if(bh->b_list != nlist) goto repeat; + next = bh->b_next_free; + if(!lru_list[nlist]) { + printk("Dirty list empty %d\n", i); + break; + } + + /* Clean buffer on dirty list? Refile it */ + if (nlist == BUF_DIRTY && !buffer_dirty(bh)) { + refile_buffer(bh); + continue; + } + + /* Unlocked buffer on locked list? Refile it */ + if (nlist == BUF_LOCKED && !buffer_locked(bh)) { + refile_buffer(bh); + continue; + } + + if (buffer_locked(bh) || !buffer_dirty(bh)) + continue; + major = MAJOR(bh->b_dev); + /* Should we write back buffers that are shared or not?? + currently dirty buffers are not shared, so it does not matter */ + next->b_count++; + bh->b_count++; + ndirty++; + bh->b_flushtime = 0; + if (major == LOOP_MAJOR) { + ll_rw_block(wrta_cmd,1, &bh); + wrta_cmd = WRITEA; + if (buffer_dirty(bh)) + --ndirty; + } + else + ll_rw_block(WRITE, 1, &bh); +#ifdef DEBUG + if(nlist != BUF_DIRTY) ncount++; +#endif + bh->b_count--; + next->b_count--; + } + } +#ifdef DEBUG + if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount); printk("sleeping again.\n"); #endif + /* If we didn't write anything, but there are still + * dirty buffers, then make the next write to a + * loop device to be a blocking write. + * This lets us block--which we _must_ do! */ + if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) { + wrta_cmd = WRITE; + continue; + } + run_task_queue(&tq_disk); + wake_up(&bdflush_done); + + /* If there are still a lot of dirty buffers around, skip the sleep + and flush some more */ + if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + + interruptible_sleep_on(&bdflush_wait); + } } } diff --git a/fs/dquot.c b/fs/dquot.c index bad8d364abfc..dfef0a63ab41 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -195,7 +195,7 @@ static inline void remove_inuse(struct dquot *dquot) static void __wait_on_dquot(struct dquot *dquot) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); add_wait_queue(&dquot->dq_wait, &wait); repeat: @@ -429,6 +429,7 @@ static void grow_dquots(void) nr_dquots++; memset((caddr_t)dquot, 0, sizeof(struct dquot)); + init_waitqueue_head(&dquot->dq_wait); /* all dquots go on the inuse_list */ put_inuse(dquot); put_dquot_head(dquot); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 6bfa7041d5f1..822207251e26 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -841,7 +841,8 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) goto end_rename; retval = -EMLINK; - if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX) + if (!new_inode && new_dir!=old_dir && + new_dir->i_nlink >= EXT2_LINK_MAX) goto end_rename; } if (!new_bh) { diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c index 7460cca62665..189b0107e154 100644 --- a/fs/hfs/dir_cap.c +++ b/fs/hfs/dir_cap.c @@ -237,10 +237,6 @@ static int cap_readdir(struct file * filp, struct hfs_cat_entry *entry; struct inode *dir = filp->f_dentry->d_inode; - if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) { - return -EBADF; - } - entry = HFS_I(dir)->entry; type = HFS_ITYPE(dir->i_ino); skip_dirs = (type == HFS_CAP_RDIR); diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c index e5ad80511674..17e53798a763 100644 --- a/fs/hfs/dir_dbl.c +++ b/fs/hfs/dir_dbl.c @@ -201,10 +201,6 @@ static int dbl_readdir(struct file * filp, struct hfs_cat_entry *entry; struct inode *dir = filp->f_dentry->d_inode; - if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) { - return -EBADF; - } - entry = HFS_I(dir)->entry; if (filp->f_pos == 0) { diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c index f9f131a17f2f..be6974b6663f 100644 --- a/fs/hfs/dir_nat.c +++ b/fs/hfs/dir_nat.c @@ -225,10 +225,6 @@ static int nat_readdir(struct file * filp, struct hfs_cat_entry *entry; struct inode *dir = filp->f_dentry->d_inode; - if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) { - return -EBADF; - } - entry = HFS_I(dir)->entry; type = HFS_ITYPE(dir->i_ino); skip_dirs = (type == HFS_NAT_HDIR); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 6c1f1558cefc..878797b8adaa 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -322,7 +322,6 @@ init_module(void) init_MUTEX(&nlmsvc_sema); nlmsvc_users = 0; nlmsvc_pid = 0; - init_waitqueue_head(&lockd_exit); nlmxdr_init(); return 0; } diff --git a/fs/minix/namei.c b/fs/minix/namei.c index c2366ae4b200..0af91237a69d 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -45,8 +45,6 @@ static struct buffer_head * minix_find_entry(struct inode * dir, struct minix_dir_entry *de; *res_dir = NULL; - if (!dir->i_sb) - return NULL; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE @@ -161,8 +159,6 @@ static int minix_add_entry(struct inode * dir, *res_buf = NULL; *res_dir = NULL; - if (!dir || !dir->i_sb) - return -ENOENT; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE @@ -331,8 +327,6 @@ static int empty_dir(struct inode * inode) struct minix_dir_entry * de; struct minix_sb_info * info; - if (!inode || !inode->i_sb) - return 1; info = &inode->i_sb->u.minix_sb; block = 0; bh = NULL; @@ -431,26 +425,12 @@ int minix_unlink(struct inode * dir, struct dentry *dentry) struct buffer_head * bh; struct minix_dir_entry * de; -repeat: retval = -ENOENT; - inode = NULL; + inode = dentry->d_inode; bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); - if (!bh) + if (!bh || de->inode != inode->i_ino) goto end_unlink; - inode = dentry->d_inode; - - retval = -EPERM; - if (de->inode != inode->i_ino) { - brelse(bh); - current->counter = 0; - schedule(); - goto repeat; - } - if (de->inode != inode->i_ino) { - retval = -ENOENT; - goto end_unlink; - } if (!inode->i_nlink) { printk("Deleting nonexistent file (%s:%lu), %d\n", kdevname(inode->i_dev), @@ -551,12 +531,6 @@ int minix_link(struct dentry * old_dentry, struct inode * dir, (((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode) /* - * rename uses retrying to avoid race-conditions: at least they should be minimal. - * it tries to allocate all the blocks, then sanity-checks, and if the sanity- - * checks fail, it tries to restart itself again. Very practical - no changes - * are done until we know everything works ok.. and then all the changes can be - * done in one fell swoop when we have claimed all the buffers needed. - * * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */ @@ -570,24 +544,15 @@ int minix_rename(struct inode * old_dir, struct dentry *old_dentry, int retval; info = &old_dir->i_sb->u.minix_sb; - goto start_up; -try_again: - brelse(old_bh); - brelse(new_bh); - brelse(dir_bh); - current->counter = 0; - schedule(); -start_up: - old_inode = new_inode = NULL; - old_bh = new_bh = dir_bh = NULL; + new_bh = dir_bh = NULL; + old_inode = old_dentry->d_inode; + new_inode = new_dentry->d_inode; old_bh = minix_find_entry(old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de); retval = -ENOENT; - if (!old_bh) + if (!old_bh || old_de->inode != old_inode->i_ino) goto end_rename; - old_inode = old_dentry->d_inode; retval = -EPERM; - new_inode = new_dentry->d_inode; new_bh = minix_find_entry(new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de); if (new_bh) { @@ -609,7 +574,8 @@ start_up: if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) goto end_rename; retval = -EMLINK; - if (!new_inode && new_dir->i_nlink >= info->s_link_max) + if (!new_inode && new_dir != old_dir && + new_dir->i_nlink >= info->s_link_max) goto end_rename; } if (!new_bh) { @@ -620,22 +586,15 @@ start_up: if (retval) goto end_rename; } -/* sanity checking before doing the rename - avoid races */ - if (new_inode && (new_de->inode != new_inode->i_ino)) - goto try_again; - if (new_de->inode && !new_inode) - goto try_again; - if (old_de->inode != old_inode->i_ino) - goto try_again; /* ok, that's it */ - old_de->inode = 0; new_de->inode = old_inode->i_ino; + old_de->inode = 0; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(old_dir); old_dir->i_version = ++event; + mark_inode_dirty(old_dir); new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(new_dir); new_dir->i_version = ++event; + mark_inode_dirty(new_dir); if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 8fc3a0994039..3ed52b390c18 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -354,16 +354,7 @@ ncp_lookup_validate(struct dentry * dentry, int flags) int len = dentry->d_name.len; struct ncpfs_inode_info finfo; __u8 __name[dentry->d_name.len + 1]; - - if (!dentry->d_inode) { - DPRINTK(KERN_DEBUG "ncp_lookup_validate: called with dentry->d_inode already NULL.\n"); - return 0; - } - if (!dir || !S_ISDIR(dir->i_mode)) { - printk(KERN_WARNING "ncp_lookup_validate: inode is NULL or not a directory.\n"); - goto finished; - } server = NCP_SERVER(dir); if (!ncp_conn_valid(server)) diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 35f5fd2eff73..b7766ba0af95 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -36,6 +36,7 @@ static void smb_put_inode(struct inode *); static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); static int smb_statfs(struct super_block *, struct statfs *, int); +static void smb_set_inode_attr(struct inode *, struct smb_fattr *); static struct super_operations smb_sops = { @@ -67,9 +68,7 @@ smb_invent_inos(unsigned long n) return ino; } -static struct smb_fattr *read_fattr = NULL; -static DECLARE_MUTEX(read_semaphore); - +/* We are always generating a new inode here */ struct inode * smb_iget(struct super_block *sb, struct smb_fattr *fattr) { @@ -77,11 +76,19 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr) pr_debug("smb_iget: %p\n", fattr); - down(&read_semaphore); - read_fattr = fattr; - result = iget(sb, fattr->f_ino); - read_fattr = NULL; - up(&read_semaphore); + result = get_empty_inode(); + result->i_sb = sb; + result->i_dev = sb->s_dev; + result->i_ino = fattr->f_ino; + memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i)); + smb_set_inode_attr(result, fattr); + if (S_ISREG(result->i_mode)) + result->i_op = &smb_file_inode_operations; + else if (S_ISDIR(result->i_mode)) + result->i_op = &smb_dir_inode_operations; + else + result->i_op = NULL; + insert_inode_hash(result) return result; } @@ -147,24 +154,9 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr) static void smb_read_inode(struct inode *inode) { - pr_debug("smb_iget: %p\n", read_fattr); - - if (!read_fattr || inode->i_ino != read_fattr->f_ino) - { - printk("smb_read_inode called from invalid point\n"); - return; - } - - inode->i_dev = inode->i_sb->s_dev; - memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i)); - smb_set_inode_attr(inode, read_fattr); - - if (S_ISREG(inode->i_mode)) - inode->i_op = &smb_file_inode_operations; - else if (S_ISDIR(inode->i_mode)) - inode->i_op = &smb_dir_inode_operations; - else - inode->i_op = NULL; + /* Now it can be called only by NFS */ + printk("smb_read_inode called from invalid point\n"); + return; } /* @@ -609,8 +601,6 @@ init_module(void) smb_current_vmalloced = 0; #endif - init_MUTEX(&read_semaphore); - return init_smb_fs(); } diff --git a/fs/super.c b/fs/super.c index f15445e4b7ca..e9454389743b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -953,16 +953,19 @@ static int do_remount(const char *dir,int flags,char *data) if (!IS_ERR(dentry)) { struct super_block * sb = dentry->d_inode->i_sb; - retval = -EINVAL; - if (dentry == sb->s_root) { - /* - * Shrink the dcache and sync the device. - */ - shrink_dcache_sb(sb); - fsync_dev(sb->s_dev); - if (flags & MS_RDONLY) - acct_auto_close(sb->s_dev); - retval = do_remount_sb(sb, flags, data); + retval = -ENODEV; + if (sb) { + retval = -EINVAL; + if (dentry == sb->s_root) { + /* + * Shrink the dcache and sync the device. + */ + shrink_dcache_sb(sb); + fsync_dev(sb->s_dev); + if (flags & MS_RDONLY) + acct_auto_close(sb->s_dev); + retval = do_remount_sb(sb, flags, data); + } } dput(dentry); } diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 18f98d353697..90804fe7c08f 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -892,7 +892,6 @@ void sysv_read_inode(struct inode * inode) for (block = 0; block < 10+1+1+1; block++) inode->u.sysv_i.i_data[block] = read3byte(&raw_inode->i_a.i_addb[3*block]); - brelse(bh); if (S_ISREG(inode->i_mode)) inode->i_op = &sysv_file_inode_operations; else if (S_ISDIR(inode->i_mode)) @@ -901,6 +900,7 @@ void sysv_read_inode(struct inode * inode) inode->i_op = &sysv_symlink_inode_operations; else init_special_inode(inode, inode->i_mode,raw_inode->i_a.i_rdev); + brelse(bh); } /* To avoid inconsistencies between inodes in memory and inodes on disk. */ diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 455d34b7acdb..d025cbc85031 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -144,8 +144,6 @@ static int sysv_add_entry(struct inode * dir, *res_buf = NULL; *res_dir = NULL; - if (!dir) - return -ENOENT; sb = dir->i_sb; if (namelen > SYSV_NAMELEN) { if (sb->sv_truncate) @@ -323,8 +321,6 @@ static int empty_dir(struct inode * inode) struct buffer_head * bh; struct sysv_dir_entry * de; - if (!inode) - return 1; block = 0; bh = NULL; pos = offset = 2*SYSV_DIRSIZE; @@ -380,22 +376,16 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry) struct buffer_head * bh; struct sysv_dir_entry * de; - inode = NULL; - bh = sysv_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); + inode = dentry->d_inode; + bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); retval = -ENOENT; - if (!bh) + if (!bh || de->inode != inode->i_ino) goto end_rmdir; - inode = dentry->d_inode; if (!empty_dir(inode)) { retval = -ENOTEMPTY; goto end_rmdir; } - if (de->inode != inode->i_ino) { - retval = -ENOENT; - goto end_rmdir; - } if (!list_empty(&dentry->d_hash)) { retval = -EBUSY; goto end_rmdir; @@ -405,9 +395,9 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry) de->inode = 0; mark_buffer_dirty(bh, 1); inode->i_nlink=0; - mark_inode_dirty(inode); dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); mark_inode_dirty(dir); d_delete(dentry); retval = 0; @@ -423,26 +413,11 @@ int sysv_unlink(struct inode * dir, struct dentry * dentry) struct buffer_head * bh; struct sysv_dir_entry * de; -repeat: retval = -ENOENT; - inode = NULL; - bh = sysv_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - if (!bh) - goto end_unlink; inode = dentry->d_inode; - - retval = -EPERM; - if (de->inode != inode->i_ino) { - brelse(bh); - current->counter = 0; - schedule(); - goto repeat; - } - if (de->inode != inode->i_ino) { - retval = -ENOENT; + bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); + if (!bh || de->inode != inode->i_ino) goto end_unlink; - } if (!inode->i_nlink) { printk("Deleting nonexistent file (%s:%lu), %d\n", kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); @@ -561,12 +536,6 @@ int sysv_link(struct dentry * old_dentry, struct inode * dir, (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode) /* - * rename uses retrying to avoid race-conditions: at least they should be minimal. - * it tries to allocate all the blocks, then sanity-checks, and if the sanity- - * checks fail, it tries to restart itself again. Very practical - no changes - * are done until we know everything works ok.. and then all the changes can be - * done in one fell swoop when we have claimed all the buffers needed. - * * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */ @@ -578,24 +547,15 @@ int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, struct sysv_dir_entry * old_de, * new_de; int retval; - goto start_up; -try_again: - brelse(old_bh); - brelse(new_bh); - brelse(dir_bh); - current->counter = 0; - schedule(); -start_up: - old_inode = new_inode = NULL; - old_bh = new_bh = dir_bh = NULL; + old_inode = old_dentry->d_inode; + new_inode = new_dentry->d_inode; + new_bh = dir_bh = NULL; old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de); retval = -ENOENT; - if (!old_bh) + if (!old_bh || old_de->inode != old_inode->i_ino) goto end_rename; - old_inode = old_dentry->d_inode; /* don't cross mnt-points */ retval = -EPERM; - new_inode = new_dentry->d_inode; new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de); if (new_bh) { @@ -617,7 +577,8 @@ start_up: if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) goto end_rename; retval = -EMLINK; - if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max) + if (!new_inode && new_dir != old_dir && + new_dir->i_nlink >= new_dir->i_sb->sv_link_max) goto end_rename; } if (!new_bh) { @@ -626,16 +587,8 @@ start_up: if (retval) goto end_rename; } -/* sanity checking before doing the rename - avoid races */ - if (new_inode && (new_de->inode != new_inode->i_ino)) - goto try_again; - if (new_de->inode && !new_inode) - goto try_again; - if (old_de->inode != old_inode->i_ino) - goto try_again; -/* ok, that's it */ - old_de->inode = 0; new_de->inode = old_inode->i_ino; + old_de->inode = 0; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; diff --git a/include/asm-alpha/hdreg.h b/include/asm-alpha/hdreg.h new file mode 100644 index 000000000000..2d9454754910 --- /dev/null +++ b/include/asm-alpha/hdreg.h @@ -0,0 +1,12 @@ +/* + * linux/include/asm-alpha/hdreg.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +#ifndef __ASMalpha_HDREG_H +#define __ASMalpha_HDREG_H + +typedef unsigned short ide_ioreg_t; + +#endif /* __ASMalpha_HDREG_H */ diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h index e8de11f12731..2ef5de935659 100644 --- a/include/asm-alpha/ide.h +++ b/include/asm-alpha/ide.h @@ -13,8 +13,6 @@ #ifdef __KERNEL__ -typedef unsigned short ide_ioreg_t; - #ifndef MAX_HWIFS #define MAX_HWIFS 4 #endif @@ -45,18 +43,42 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index) } } -static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +static __inline__ void 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; } +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ +#ifdef __DO_I_NEED_THIS + hw_regs_t hw; + int index; + + for (index = 0; index < MAX_HWIFS; index++) { + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, 0); + hw.irq = ide_default_irq(ide_default_io_base(index)); + ide_register_hw(&hw, NULL); + } +#endif /* __DO_I_NEED_THIS */ +} + typedef union { unsigned all : 8; /* all of the bits together */ struct { @@ -68,51 +90,19 @@ typedef union { } b; } select_t; -static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *device, void *dev_id) -{ - return request_irq(irq, handler, flags, device, dev_id); -} - -static __inline__ void ide_free_irq(unsigned int irq, void *dev_id) -{ - free_irq(irq, dev_id); -} - -static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent) -{ - return check_region(from, extent); -} - -static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name) -{ - request_region(from, extent, name); -} - -static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent) -{ - release_region(from, extent); -} +#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) +#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) +#define ide_check_region(from,extent) check_region((from), (extent)) +#define ide_request_region(from,extent,name) request_region((from), (extent), (name)) +#define ide_release_region(from,extent) release_region((from), (extent)) /* * The following are not needed for the non-m68k ports */ -static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port) -{ - return(1); -} - -static __inline__ void ide_fix_driveid(struct hd_driveid *id) -{ -} - -static __inline__ void ide_release_lock (int *ide_lock) -{ -} - -static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data) -{ -} +#define ide_ack_intr(hwif) (1) +#define ide_fix_driveid(id) do {} while (0) +#define ide_release_lock(lock) do {} while (0) +#define ide_get_lock(lock, hdlr, data) do {} while (0) #endif /* __KERNEL__ */ diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h index dc976cb5fca7..f908f74640ad 100644 --- a/include/asm-alpha/io.h +++ b/include/asm-alpha/io.h @@ -356,6 +356,12 @@ out: #endif #define RTC_ALWAYS_BCD 0 +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + #endif /* __KERNEL__ */ #endif /* __ALPHA_IO_H */ diff --git a/include/asm-arm/arch-arc/ide.h b/include/asm-arm/arch-arc/ide.h index 2fc6ce282855..031225380f39 100644 --- a/include/asm-arm/arch-arc/ide.h +++ b/include/asm-arm/arch-arc/ide.h @@ -19,33 +19,32 @@ * Set up a hw structure for a specified data port, control port and IRQ. * This should follow whatever the default interface uses. */ -static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; - memset(hw, 0, sizeof(*hw)); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hw->io_ports[i] = reg; reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + hw->irq = *irq; } /* * This registers the standard ports for this architecture with the IDE * driver. */ -static __inline__ void -ide_init_default_hwifs(void) +static __inline__ void ide_init_default_hwifs(void) { #ifdef CONFIG_ARCH_A5K hw_regs_t hw; - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK); + memset(hw, 0, sizeof(*hw)); + + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_HARDDISK; ide_register_hw(&hw, NULL); #endif } diff --git a/include/asm-arm/arch-ebsa285/ide.h b/include/asm-arm/arch-ebsa285/ide.h index b0071a45b2b0..d86a6f98a93d 100644 --- a/include/asm-arm/arch-ebsa285/ide.h +++ b/include/asm-arm/arch-ebsa285/ide.h @@ -12,27 +12,32 @@ * Set up a hw structure for a specified data port, control port and IRQ. * This should follow whatever the default interface uses. */ -static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; - memset(hw, 0, sizeof(*hw)); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hw->io_ports[i] = reg; reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + hw->irq = *irq; } /* * This registers the standard ports for this architecture with the IDE * driver. */ -static __inline__ void -ide_init_default_hwifs(void) +static __inline__ void ide_init_default_hwifs(void) { +#if 0 + hw_regs_t hw; + + memset(hw, 0, sizeof(*hw)); + + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_HARDDISK; + ide_register_hw(&hw, NULL); +#endif } diff --git a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h index ccbc7cf76aa6..9826f15f5934 100644 --- a/include/asm-arm/arch-rpc/ide.h +++ b/include/asm-arm/arch-rpc/ide.h @@ -12,31 +12,30 @@ * Set up a hw structure for a specified data port, control port and IRQ. * This should follow whatever the default interface uses. */ -static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; - memset(hw, 0, sizeof(*hw)); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hw->io_ports[i] = reg; reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + hw->irq = *irq; } /* * This registers the standard ports for this architecture with the IDE * driver. */ -static __inline__ void -ide_init_default_hwifs(void) +static __inline__ void ide_init_default_hwifs(void) { hw_regs_t hw; - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK); + memset(hw, 0, sizeof(*hw)); + + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_HARDDISK; ide_register_hw(&hw, NULL); } diff --git a/include/asm-arm/hdreg.h b/include/asm-arm/hdreg.h new file mode 100644 index 000000000000..81bc05e16260 --- /dev/null +++ b/include/asm-arm/hdreg.h @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/hdreg.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +#ifndef __ASMARM_HDREG_H +#define __ASMARM_HDREG_H + +typedef unsigned long ide_ioreg_t; + +#endif /* __ASMARM_HDREG_H */ + diff --git a/include/asm-arm/ide.h b/include/asm-arm/ide.h index 76da8806b6a4..6bd9d3c02045 100644 --- a/include/asm-arm/ide.h +++ b/include/asm-arm/ide.h @@ -48,4 +48,4 @@ typedef union { #endif /* __KERNEL__ */ -#endif /* __ASMi386_IDE_H */ +#endif /* __ASMARM_IDE_H */ diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 35db8e667f05..cfa021bcdf68 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -189,10 +189,21 @@ __IO(l,"",long) #define inl_p(port) __inl_p((port)) #endif -#endif +/* Nothing to do */ +#ifndef dma_cache_inv +#define dma_cache_inv(_start,_size) do { } while (0) +#endif +#ifndef dma_cache_wback +#define dma_cache_wback(_start,_size) do { } while (0) #ifndef ARCH_READWRITE +#ifndef dma_cache_wback_inv +#define dma_cache_wback_inv(_start,_size) do { } while (0) +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_IO_H */ /* for panic */ #include diff --git a/include/asm-i386/hdreg.h b/include/asm-i386/hdreg.h new file mode 100644 index 000000000000..1ad5c073941c --- /dev/null +++ b/include/asm-i386/hdreg.h @@ -0,0 +1,12 @@ +/* + * linux/include/asm-i386/hdreg.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +#ifndef __ASMi386_HDREG_H +#define __ASMi386_HDREG_H + +typedef unsigned short ide_ioreg_t; + +#endif /* __ASMi386_HDREG_H */ diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h index a6d1fc868e9f..6876f9f60ef8 100644 --- a/include/asm-i386/ide.h +++ b/include/asm-i386/ide.h @@ -13,10 +13,8 @@ #ifdef __KERNEL__ -typedef unsigned short ide_ioreg_t; - #ifndef MAX_HWIFS -#define MAX_HWIFS 6 +#define MAX_HWIFS 8 #endif #define ide__sti() __sti() @@ -49,18 +47,38 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index) } } -static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +static __inline__ void 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; } +static __inline__ void ide_init_default_hwifs(void) +{ +#ifdef __DO_I_NEED_THIS + hw_regs_t hw; + int index; + + for(index = 0; index < MAX_HWIFS; index++) { + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); + hw.irq = ide_default_irq(ide_default_io_base(index)); + ide_register_hw(&hw, NULL); + } +#endif /* __DO_I_NEED_THIS */ +} + typedef union { unsigned all : 8; /* all of the bits together */ struct { @@ -72,51 +90,19 @@ typedef union { } b; } select_t; -static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *device, void *dev_id) -{ - return request_irq(irq, handler, flags, device, dev_id); -} - -static __inline__ void ide_free_irq(unsigned int irq, void *dev_id) -{ - free_irq(irq, dev_id); -} - -static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent) -{ - return check_region(from, extent); -} - -static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name) -{ - request_region(from, extent, name); -} - -static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent) -{ - release_region(from, extent); -} +#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) +#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) +#define ide_check_region(from,extent) check_region((from), (extent)) +#define ide_request_region(from,extent,name) request_region((from), (extent), (name)) +#define ide_release_region(from,extent) release_region((from), (extent)) /* * The following are not needed for the non-m68k ports */ -static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port) -{ - return(1); -} - -static __inline__ void ide_fix_driveid(struct hd_driveid *id) -{ -} - -static __inline__ void ide_release_lock (int *ide_lock) -{ -} - -static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data) -{ -} +#define ide_ack_intr(hwif) (1) +#define ide_fix_driveid(id) do {} while (0) +#define ide_release_lock(lock) do {} while (0) +#define ide_get_lock(lock, hdlr, data) do {} while (0) #endif /* __KERNEL__ */ diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h index 155ff14193c3..93fd0c1b52d3 100644 --- a/include/asm-i386/io.h +++ b/include/asm-i386/io.h @@ -183,6 +183,12 @@ out: return retval; } +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index c5b82c84bec4..870fad7b2815 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -34,7 +34,7 @@ struct semaphore { int waking; wait_queue_head_t wait; #if WAITQUEUE_DEBUG - int __magic; + long __magic; #endif }; diff --git a/include/asm-m68k/hdreg.h b/include/asm-m68k/hdreg.h new file mode 100644 index 000000000000..16249bd892a4 --- /dev/null +++ b/include/asm-m68k/hdreg.h @@ -0,0 +1,13 @@ +/* + * linux/include/asm-m68k/hdreg.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +#ifndef _M68K_HDREG_H +#define _M68K_HDREG_H + +typedef unsigned int q40ide_ioreg_t; +typedef unsigned char * ide_ioreg_t; + +#endif /* _M68K_HDREG_H */ diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h index da5753ee77f5..e4a83371d5e9 100644 --- a/include/asm-m68k/ide.h +++ b/include/asm-m68k/ide.h @@ -45,13 +45,6 @@ #include #endif - -typedef unsigned int q40ide_ioreg_t; - - -typedef unsigned char * ide_ioreg_t; - - #ifndef MAX_HWIFS #define MAX_HWIFS 4 /* same as the other archs */ #endif @@ -65,19 +58,39 @@ static __inline__ int ide_default_irq(ide_ioreg_t base) else return 0; } +int q40ide_default_io_base(int); + +static __inline__ ide_ioreg_t ide_default_io_base(int index) +{ + if (MACH_IS_Q40) + return q40ide_default_io_base(index); + else return 0; +} /* * Can we do this in a generic manner?? */ -void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq); +void q40_ide_init_hwif_ports (hw_regs_t *hw, q40ide_ioreg_t data_port, q40ide_ioreg_t ctrl_port, int *irq); -static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { #ifdef CONFIG_Q40 - if (MACH_IS_Q40) - return q40_ide_init_hwif_ports((q40ide_ioreg_t *)p,(q40ide_ioreg_t)base,irq); + if (MACH_IS_Q40) + return q40_ide_init_hwif_ports(hw, (q40ide_ioreg_t) data_port, (q40ide_ioreg_t) ctrl_port, irq); #endif - printk("ide_init_hwif_ports: must not be called\n"); + printk("ide_init_hwif_ports: must not be called\n"); +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ } typedef union { @@ -487,7 +500,7 @@ static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, #endif /* CONFIG_ATARI */ } -#define ide_ack_intr(hwif) ((hwif)->ack_intr ? (hwif)->ack_intr(hwif) : 1) +#define ide_ack_intr(hwif) ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) /* * On the Atari, we sometimes can't enable interrupts: diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h index 168077b26e89..7843b8f092ed 100644 --- a/include/asm-m68k/io.h +++ b/include/asm-m68k/io.h @@ -72,6 +72,12 @@ extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size extern void iounmap(void *addr); +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + #endif /* __KERNEL__ */ #endif /* _M68K_IO_H */ diff --git a/include/asm-mips/hdreg.h b/include/asm-mips/hdreg.h new file mode 100644 index 000000000000..189dfc55c3cb --- /dev/null +++ b/include/asm-mips/hdreg.h @@ -0,0 +1,18 @@ +/* $Id: hdreg.h,v 1.4 1998/05/08 21:05:26 davem Exp $ + * + * linux/include/asm-mips/hdreg.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +/* + * This file contains the MIPS architecture specific IDE code. + */ + +#ifndef __ASM_MIPS_HDREG_H +#define __ASM_MIPS_HDREG_H + +typedef unsigned short ide_ioreg_t; + +#endif /* __ASM_MIPS_HDREG_H */ + diff --git a/include/asm-mips/ide.h b/include/asm-mips/ide.h index f9aa1e57dd64..81fda3fbbc90 100644 --- a/include/asm-mips/ide.h +++ b/include/asm-mips/ide.h @@ -14,8 +14,6 @@ #ifdef __KERNEL__ -typedef unsigned short ide_ioreg_t; - #ifndef MAX_HWIFS #define MAX_HWIFS 6 #endif @@ -25,7 +23,7 @@ typedef unsigned short ide_ioreg_t; struct ide_ops { int (*ide_default_irq)(ide_ioreg_t base); ide_ioreg_t (*ide_default_io_base)(int index); - 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); int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id); @@ -48,10 +46,29 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index) return ide_ops->ide_default_io_base(index); } -static __inline__ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, - int *irq) +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { - ide_ops->ide_init_hwif_ports(p, base, irq); + ide_ops->ide_init_hwif_ports(hw->io_ports, data_port, ctrl_port, &hw->irq); + + hw->irq = ide_ops->ide_default_irq(data_port); +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ +#ifdef __DO_I_NEED_THIS + hw_regs_t hw; + int index; + + for (index = 0; index < MAX_HWIFS; index++) { + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, 0); + hw.irq = ide_default_irq(ide_default_io_base(index)); + ide_register_hw(&hw, NULL); + } +#endif /* __DO_I_NEED_THIS */ } typedef union { @@ -96,26 +113,10 @@ static __inline__ void ide_release_region(ide_ioreg_t from, /* * The following are not needed for the non-m68k ports */ -static __inline__ int ide_ack_intr (ide_ioreg_t status_port, - ide_ioreg_t irq_port) -{ - return 1; -} - -static __inline__ void ide_fix_driveid(struct hd_driveid *id) -{ -} - -static __inline__ void ide_release_lock (int *ide_lock) -{ -} - -static __inline__ void ide_get_lock (int *ide_lock, - void (*handler)(int, void *, - struct pt_regs *), - void *data) -{ -} +#define ide_ack_intr(hwif) (1) +#define ide_fix_driveid(id) do {} while (0) +#define ide_release_lock(lock) do {} while (0) +#define ide_get_lock(lock, hdlr, data) do {} while (0) #endif /* __KERNEL__ */ diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index 2319c27c9963..d167d7ccdc51 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -389,4 +389,8 @@ __OUTS(w,l,4) extern void (*dma_cache_wback_inv)(unsigned long start, unsigned long size); extern void (*dma_cache_inv)(unsigned long start, unsigned long size); +/* Nothing to do */ + +#define dma_cache_wback(_start,_size) do { } while (0) + #endif /* __ASM_MIPS_IO_H */ diff --git a/include/asm-ppc/hdreg.h b/include/asm-ppc/hdreg.h new file mode 100644 index 000000000000..58123536b31e --- /dev/null +++ b/include/asm-ppc/hdreg.h @@ -0,0 +1,17 @@ +/* + * linux/include/asm-ppc/hdreg.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +/* + * This file contains the ppc architecture specific IDE code. + */ + +#ifndef __ASMPPC_HDREG_H +#define __ASMPPC_HDREG_H + +typedef unsigned int ide_ioreg_t; + +#endif /* __ASMPPC_HDREG_H */ + diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h index c53267b77e0a..30a53876ee84 100644 --- a/include/asm-ppc/ide.h +++ b/include/asm-ppc/ide.h @@ -18,7 +18,7 @@ #define MAX_HWIFS 4 #endif -typedef unsigned int ide_ioreg_t; +#include #ifdef __KERNEL__ @@ -49,16 +49,17 @@ struct ide_machdep_calls { void (*release_region)(ide_ioreg_t from, unsigned int extent); void (*fix_driveid)(struct hd_driveid *id); - void (*ide_init_hwif)(ide_ioreg_t *p, - ide_ioreg_t base, - int *irq); + void (*ide_init_hwif)(hw_regs_t *hw, + ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, + int *irq); int io_base; }; extern struct ide_machdep_calls ppc_ide_md; -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); void ide_insw(ide_ioreg_t port, void *buf, int ns); void ide_outsw(ide_ioreg_t port, void *buf, int ns); void ppc_generic_ide_fix_driveid(struct hd_driveid *id); @@ -90,6 +91,20 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index) return ppc_ide_md.default_io_base(index); } +static __inline__ void ide_init_default_hwifs(void) +{ +#ifdef __DO_I_NEED_THIS + hw_regs_t hw; + int index; + + for(index = 0; index < MAX_HWIFS; index++) { + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); + hw.irq = ide_default_irq(ide_default_io_base(index)); + ide_register_hw(&hw, NULL); + } +#endif /* __DO_I_NEED_THIS */ +} + static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent) { return ppc_ide_md.check_region(from, extent); @@ -131,21 +146,13 @@ typedef union { } b; } select_t; -static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *device, void *dev_id) -{ - return request_irq(irq, handler, flags, device, dev_id); -} - -static __inline__ void ide_free_irq(unsigned int irq, void *dev_id) -{ - free_irq(irq, dev_id); -} +#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) +#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) /* * The following are not needed for the non-m68k ports */ -#define ide_ack_intr(base, irq) (1) +#define ide_ack_intr(hwif) (1) #define ide_release_lock(lock) do {} while (0) #define ide_get_lock(lock, hdlr, data) do {} while (0) diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 92ac97729ff5..bd8a7d16cd7d 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -277,6 +277,13 @@ static inline int check_signature(unsigned long io_addr, out: return retval; } + +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h index a26453b2fc1f..80596ffcb84d 100644 --- a/include/asm-sparc/io.h +++ b/include/asm-sparc/io.h @@ -162,4 +162,10 @@ static __inline__ void *sparc_dvma_malloc(int size, char *name, __u32 *dvmaaddr_ #define virt_to_phys(x) __pa((unsigned long)(x)) #define phys_to_virt(x) __va((unsigned long)(x)) +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + #endif /* !(__SPARC_IO_H) */ diff --git a/include/asm-sparc64/hdreg.h b/include/asm-sparc64/hdreg.h new file mode 100644 index 000000000000..06885e3ce73c --- /dev/null +++ b/include/asm-sparc64/hdreg.h @@ -0,0 +1,13 @@ +/* $Id: hdreg.h,v 1.9 1998/05/08 21:05:28 davem Exp $ + * hdreg.h: Ultra/PCI specific IDE glue. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + */ + +#ifndef __SPARC64_HDREG_H +#define __SPARC64_HDREG_H + +typedef unsigned long ide_ioreg_t; + +#endif /* __SPARC64_HDREG_H */ diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h index 191b95cb2c8e..6666e97376ba 100644 --- a/include/asm-sparc64/ide.h +++ b/include/asm-sparc64/ide.h @@ -12,8 +12,6 @@ #include -typedef unsigned long ide_ioreg_t; - #undef MAX_HWIFS #define MAX_HWIFS 2 @@ -29,21 +27,42 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index) return 0; } -static __inline__ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { + ide_ioreg_t reg = data_port; int i; - /* These are simply offsets from base. */ - for (i = 0; i < 8; i++) - *p++ = base++; - /* PCI code needs to figure out these. */ - for ( ; i < 10; i++) - *p++ = 0; - /* PCI code needs to figure out this. */ + 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) *irq = 0; } +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ +#ifdef __DO_I_NEED_THIS + hw_regs_t hw; + int index; + + for (index = 0; index < MAX_HWIFS; index++) { + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, 0); + hw.irq = ide_default_irq(ide_default_io_base(index)); + ide_register_hw(&hw, NULL); + } +#endif /* __DO_I_NEED_THIS */ +} + typedef union { unsigned int all : 8; /* all of the bits together */ struct { @@ -92,11 +111,6 @@ static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size) #undef HD_DATA #define HD_DATA ((ide_ioreg_t)0) -static __inline__ int ide_ack_intr(ide_ioreg_t status_port, ide_ioreg_t irq_port) -{ - return 1; -} - /* From m68k code... */ #ifdef insl @@ -255,13 +269,12 @@ static __inline__ void ide_fix_driveid(struct hd_driveid *id) } } -static __inline__ void ide_release_lock (int *ide_lock) -{ -} - -static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data) -{ -} +/* + * The following are not needed for the non-m68k ports + */ +#define ide_ack_intr(hwif) (1) +#define ide_release_lock(lock) do {} while (0) +#define ide_get_lock(lock, hdlr, data) do {} while (0) #endif /* __KERNEL__ */ diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index c9e3c84609d7..3af29e5fd6da 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -226,4 +226,10 @@ extern void *sparc_alloc_io(u32 pa, void *va, int sz, char *name, extern void sparc_free_io (void *va, int sz); extern void *sparc_dvma_malloc (int sz, char *name, __u32 *dvma_addr); +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + #endif /* !(__SPARC64_IO_H) */ diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index e467ae9b6545..2fee75fec10e 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -93,7 +93,43 @@ #define SMART_STATUS 0xda #define SMART_AUTO_OFFLINE 0xdb +/* WIN_SETFEATURES sub-commands */ + +#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ +#define SETFEATURES_XFER 0x03 /* Set transfer mode */ +# define XFER_UDMA_4 0x44 /* 0100|0100 */ +# define XFER_UDMA_3 0x43 /* 0100|0011 */ +# define XFER_UDMA_2 0x42 /* 0100|0010 */ +# define XFER_UDMA_1 0x41 /* 0100|0001 */ +# define XFER_UDMA_0 0x40 /* 0100|0000 */ +# define XFER_MW_DMA_2 0x22 /* 0010|0010 */ +# define XFER_MW_DMA_1 0x21 /* 0010|0001 */ +# define XFER_MW_DMA_0 0x20 /* 0010|0000 */ +# define XFER_SW_DMA_2 0x12 /* 0001|0010 */ +# define XFER_SW_DMA_1 0x11 /* 0001|0001 */ +# define XFER_SW_DMA_0 0x10 /* 0001|0000 */ +# define XFER_PIO_4 0x0C /* 0000|1100 */ +# define XFER_PIO_3 0x0B /* 0000|1011 */ +# define XFER_PIO_2 0x0A /* 0000|1010 */ +# define XFER_PIO_1 0x09 /* 0000|1001 */ +# define XFER_PIO_0 0x08 /* 0000|1000 */ +# define XFER_PIO_SLOW 0x00 /* 0000|0000 */ +#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ +#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ +#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ +#define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ +#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ +#define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ +#define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ +#define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ +#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ +#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ +#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ +#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */ +#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt */ + /* WIN_SECURITY sub-commands */ + #define SECURITY_SET_PASSWORD 0xBA /* 0xF1 */ #define SECURITY_UNLOCK 0xBB /* 0xF2 */ #define SECURITY_ERASE_PREPARE 0xBC /* 0xF3 */ diff --git a/include/linux/hdsmart.h b/include/linux/hdsmart.h new file mode 100644 index 000000000000..10bd7249d8e0 --- /dev/null +++ b/include/linux/hdsmart.h @@ -0,0 +1,61 @@ +#ifndef _LINUX_HDSMART_H +#define _LINUX_HDSMART_H + +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. + */ + +#define NR_ATTRIBUTES 30 + +typedef struct threshold_s { + unsigned char id; + unsigned char threshold; + unsigned char reserved[10]; +} __attribute__ ((packed)) threshold_t; + +typedef struct thresholds_s { + unsigned short revision; + threshold_t thresholds[NR_ATTRIBUTES]; + unsigned char reserved[18]; + unsigned char vendor[131]; + unsigned char checksum; +} __attribute__ ((packed)) thresholds_t; + +typedef struct value_s { + unsigned char id; + unsigned short status; + unsigned char value; + unsigned char vendor[8]; +} __attribute__ ((packed)) value_t; + +typedef struct values_s { + unsigned short revision; + value_t values[NR_ATTRIBUTES]; + unsigned char offline_status; + unsigned char vendor1; + unsigned short offline_timeout; + unsigned char vendor2; + unsigned char offline_capability; + unsigned short smart_capability; + unsigned char reserved[16]; + unsigned char vendor[125]; + unsigned char checksum; +} __attribute__ ((packed)) values_t; + +#if !defined(__KERNEL__) || defined(_IDE_DISK_C) + +#define NR_OFFLINE_TEXTS 5 +struct { + unsigned char value; + char *text; +} offline_status_text[NR_OFFLINE_TEXTS] = { + { 0x00, "NeverStarted" }, + { 0x02, "Completed" }, + { 0x04, "Suspended" }, + { 0x05, "Aborted" }, + { 0x06, "Failed" } +}; +#endif /* !defined(__KERNEL__) || defined(_IDE_DISK_C) */ + +#endif /* _LINUX_HDSMART_H */ diff --git a/include/linux/ide.h b/include/linux/ide.h new file mode 100644 index 000000000000..a06b9f0da4d3 --- /dev/null +++ b/include/linux/ide.h @@ -0,0 +1,821 @@ +#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 +#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]); \ +} + +/* + * Check for an interrupt and acknowledge the interrupt status + */ +struct hwif_s; +typedef int (ide_ack_intr_t)(struct hwif_s *); + +/* + * Structure to hold all information about the location of this port + */ +typedef struct hw_regs_s { + ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ + int irq; /* our irq number */ + ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ + void *priv; /* interface specific data */ +} hw_regs_t; + +/* + * Register new hardware with ide + */ +int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp); + +/* + * Set up hw_regs_t structure before calling ide_register_hw (optional) + */ +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); + +#include + +/* + * 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 *) */ + wait_queue_head_t 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 */ +#if 1 + struct thresholds_s *smart_thresholds; + struct values_s *smart_values; +#else + thresholds_t smart_thresholds; + values_t smart_values; +#endif + } 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_bad_drive, ide_dma_good_drive + } 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_cy82c693, 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 */ + hw_regs_t hw; /* Hardware info */ + 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); + +void ide_delay_50ms (void); + +/* + * 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 +#if MAX_HWIFS > 6 +void do_ide6_request (void); +#endif +#if MAX_HWIFS > 7 +void do_ide7_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, ide_dma_action_t func); +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 + +/* This is too ugly to live! */ +#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 --git a/include/linux/isdn.h b/include/linux/isdn.h index 0b61899c0c92..f504bbde8e48 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -626,8 +626,7 @@ typedef struct modem_info { atemu emu; /* AT-emulator data */ struct termios normal_termios; /* For saving termios structs */ struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait, close_wait; } modem_info; #define ISDN_MODEM_WINSIZE 8 @@ -683,8 +682,8 @@ struct ippp_struct { struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */ struct ippp_buf_queue *first; /* pointer to (current) first packet */ struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */ - struct wait_queue *wq; - struct wait_queue *wq1; + wait_queue_head_t wq; + wait_queue_head_t wql; struct task_struct *tk; unsigned int mpppcfg; unsigned int pppcfg; @@ -748,7 +747,7 @@ typedef struct { ulong flags; /* Flags */ int channels; /* Number of channels */ int reject_bus; /* Flag: Reject rejected call on bus*/ - struct wait_queue *st_waitq; /* Wait-Queue for status-read's */ + wait_queue_head_t st_waitq; /* Wait-Queue for status-read's */ int maxbufsize; /* Maximum Buffersize supported */ unsigned long pktcount; /* Until now: unused */ int running; /* Flag: Protocolcode running */ @@ -761,8 +760,8 @@ typedef struct { unsigned long DLEflag; /* Flags: Insert DLE at next read */ #endif struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */ - struct wait_queue **rcv_waitq; /* Wait-Queues for B-Channel-Reads */ - struct wait_queue **snd_waitq; /* Wait-Queue for B-Channel-Send's */ + wait_queue_head_t *rcv_waitq; /* array of Wait-Queues for B-Channel-Reads */ + wait_queue_head_t *snd_waitq; /* array of Wait-Queue for B-Channel-Sends */ char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */ } driver; @@ -778,7 +777,7 @@ typedef struct isdn_devt { /* see ISDN_TIMER_..defines */ int global_flags; infostruct *infochain; /* List of open info-devs. */ - struct wait_queue *info_waitq; /* Wait-Queue for isdninfo */ + wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */ struct timer_list timer; /* Misc.-function Timer */ int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */ int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */ diff --git a/include/linux/major.h b/include/linux/major.h index 66e7ee8291f4..4b7d75ac80e0 100644 --- a/include/linux/major.h +++ b/include/linux/major.h @@ -92,6 +92,9 @@ #define SPECIALIX_NORMAL_MAJOR 75 #define SPECIALIX_CALLOUT_MAJOR 76 +#define IDE6_MAJOR 88 +#define IDE7_MAJOR 89 + #define UNIX98_PTY_MASTER_MAJOR 128 #define UNIX98_PTY_MAJOR_COUNT 8 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) diff --git a/include/linux/pci.h b/include/linux/pci.h index 552b9cb1f9ba..1617bc6a6077 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -516,6 +516,7 @@ #define PCI_VENDOR_ID_PROMISE 0x105a #define PCI_DEVICE_ID_PROMISE_20246 0x4d33 +#define PCI_DEVICE_ID_PROMISE_20262 0x4d38 #define PCI_DEVICE_ID_PROMISE_5300 0x5300 #define PCI_VENDOR_ID_N9 0x105d @@ -659,11 +660,14 @@ #define PCI_DEVICE_ID_AL_M1523 0x1523 #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 +#define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1543 0x1543 #define PCI_DEVICE_ID_AL_M3307 0x3307 #define PCI_DEVICE_ID_AL_M4803 0x5215 #define PCI_DEVICE_ID_AL_M5219 0x5219 #define PCI_DEVICE_ID_AL_M5229 0x5229 #define PCI_DEVICE_ID_AL_M5237 0x5237 +#define PCI_DEVICE_ID_AL_M5243 0x5243 #define PCI_DEVICE_ID_AL_M7101 0x7101 #define PCI_VENDOR_ID_MITSUBISHI 0x10ba diff --git a/include/linux/quota.h b/include/linux/quota.h index 2c4a5bcef2b6..a3e76e138128 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -170,7 +170,7 @@ struct dquot { struct list_head dq_free; /* free list element */ struct dquot *dq_hash_next; /* Pointer to next in dquot_hash */ struct dquot **dq_hash_pprev; /* Pointer to previous in dquot_hash */ - struct wait_queue *dq_wait; /* Pointer to waitqueue */ + wait_queue_head_t dq_wait; /* Pointer to waitqueue */ int dq_count; /* Reference count */ /* fields after this point are cleared when invalidating */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2089a9710f3c..82d5da6e9685 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -449,6 +449,14 @@ extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list) * Add data to an sk_buff */ +extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) +{ + unsigned char *tmp=skb->tail; + skb->tail+=len; + skb->len+=len; + return tmp; +} + extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp=skb->tail; @@ -463,6 +471,13 @@ here: ; return tmp; } +extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) +{ + skb->data-=len; + skb->len+=len; + return skb->data; +} + extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len) { skb->data-=len; diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 119b60eec11c..52c1e0f312e5 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -278,6 +278,7 @@ struct video_unit #define VID_HARDWARE_TYPHOON 19 #define VID_HARDWARE_VINO 20 /* Reserved for SGI Indy Vino */ #define VID_HARDWARE_CADET 21 /* Cadet radio */ +#define VID_HARDWARE_CPIA 22 /* * Initialiser list diff --git a/include/net/tcp.h b/include/net/tcp.h index 2d91a8d43bf5..6d7dc75dc132 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -728,7 +728,7 @@ extern __inline__ int tcp_raise_window(struct sock *sk) */ extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) { - __u32 snd_wnd_packets = tp->snd_wnd / tp->mss_cache; + __u32 snd_wnd_packets = tp->snd_wnd / max(tp->mss_cache, 1); return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2); } diff --git a/init/main.c b/init/main.c index d8f92fd09163..09d8af921143 100644 --- a/init/main.c +++ b/init/main.c @@ -416,6 +416,10 @@ static struct dev_name_struct { { "hdj", 0x3840 }, { "hdk", 0x3900 }, { "hdl", 0x3940 }, + { "hdm", 0x5800 }, + { "hdn", 0x5840 }, + { "hdo", 0x5900 }, + { "hdp", 0x5940 }, #endif #ifdef CONFIG_BLK_DEV_SD { "sda", 0x0800 }, @@ -929,7 +933,11 @@ static int __init checksetup(char *line) #ifdef CONFIG_BLK_DEV_IDE /* ide driver needs the basic string, rather than pre-processed values */ - if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '=')) { + if (!strncmp(line,"ide",3) || +#ifdef CONFIG_BLK_DEV_VIA82C586 + !strncmp(line,"splitfifo",9) || +#endif /* CONFIG_BLK_DEV_VIA82C586 */ + (!strncmp(line,"hd",2) && line[2] != '=')) { ide_setup(line); return 1; }