encountered a bug! If you're unsure what version you're currently
running, the suggested command should tell you.
-- Kernel modutils 2.3.5 ; insmod -V
+- Kernel modutils 2.3.6 ; insmod -V
- Gnu C 2.7.2.3 ; gcc --version
- Binutils 2.8.1.0.23 ; ld -v
- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc*
Modules utilities
=================
-The 2.3.5 release:
-ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.5.tar.gz
+The 2.3.6 release:
+ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.6.tar.gz
Procps utilities
================
on the Alpha. The only time you would ever not say Y is to say M in
order to debug the code. Say Y unless you know what you are doing.
-Big memory support
+Support for over 1Gig of memory
CONFIG_BIGMEM
- Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory.
+ Linux can use up to 1 Gigabytes (= 2^30 bytes) of physical memory.
If you are compiling a kernel which will never run on a machine with
more than 1 Gigabyte, answer N here. Otherwise, say Y.
- The actual amount of physical memory should be specified using a
+ The actual amount of physical memory may need to be specified using a
kernel command line option such as "mem=256M". (Try "man bootparam"
or see the documentation of your boot loader (lilo or loadlin) about
how to pass options to the kernel at boot time. The lilo procedure
If in doubt, say N.
-Winbond SL82c105 support
-CONFIG_BLK_DEV_SL82C105
- If you have a Winbond SL82c105 IDE controller, say Y here to enable
- special configuration for this chip. This is common on various CHRP
- motherboards, but could be used elsewhere. If in doubt, say Y.
-
Boot off-board chipsets first support
CONFIG_BLK_DEV_OFFBOARD
Normally, IDE controllers built into the motherboard (on-board
It is normally safe to answer Y to this question unless your
motherboard uses a VIA VP2 chipset, in which case you should say N.
-Other IDE chipset support
-CONFIG_IDE_CHIPSETS
- Say Y here if you want to include enhanced support for various IDE
- interface chipsets used on motherboards and add-on cards. You can
- then pick your particular IDE chip from among the following options.
- This enhanced support may be necessary for Linux to be able to
- access the 3rd/4th drives in some systems. It may also enable
- setting of higher speed I/O rates to improve system performance with
- these chipsets. Most of these also require special kernel boot
- parameters to actually turn on the support at runtime; you can find
- a list of these in the file Documentation/ide.txt.
-
- People with SCSI-only systems can say N here.
-
-Generic 4 drives/port support
-CONFIG_BLK_DEV_4DRIVES
- Certain older chipsets, including the Tekram 690CD, use a single set
- of I/O ports at 0x1f0 to control up to four drives, instead of the
- customary two drives per port. Support for this can be enabled at
- runtime using the "ide0=four" kernel boot parameter if you say Y
- here.
-
-DTC-2278 support
-CONFIG_BLK_DEV_DTC2278
- This driver is enabled at runtime using the "ide0=dtc2278" kernel
- boot parameter. It enables support for the secondary IDE interface
- of the DTC-2278 card, and permits faster I/O speeds to be set as
- well. See the Documentation/ide.txt and drivers/block/dtc2278.c
- files for more info.
-
-Holtek HT6560B support
-CONFIG_BLK_DEV_HT6560B
- This driver is enabled at runtime using the "ide0=ht6560b" kernel
- boot parameter. It enables support for the secondary IDE interface
- of the Holtek card, and permits faster I/O speeds to be set as well.
- See the Documentation/ide.txt and drivers/block/ht6560b.c files for
- more info.
+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 say Y here, and preferably also to "Use DMA by default when
+ available".
-PROMISE DC4030 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC4030
- This driver provides support for the secondary IDE interface and
- cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
- is known to incur timeouts/retries during heavy I/O to drives
- attached to the secondary interface. CDROM and TAPE devices are not
- supported yet. This driver is enabled at runtime using the
- "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
- and drivers/block/pdc4030.c files for more info.
+ Please read the comments at the top of drivers/block/aec6210.c
-PS/2 ESDI hard disk support
-CONFIG_BLK_DEV_PS2
- Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
- hard disk.
-
- If you want to compile the driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read Documentation/modules.txt. The module will be
- called ps2esdi.o.
+ALI M15x3 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_ALI15X3
+ This driver ensures (U)DMA support for ALI 1543 and 1543C,
+ 1535, 1535D onboard chipsets. It also tests for Simplex mode and
+ enables normal dual channel support.
-Tekram TRM290 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_TRM290
- This driver adds support for bus master DMA transfers
- using the Tekram TRM290 PCI IDE chip. Volunteers are
- needed for further tweaking and development.
- Please read the comments at the top of drivers/block/trm290.c.
+ If you say Y here, you also need to say Y to "Use DMA by default
+ when available", above.
-OPTi 82C621 enhanced support (EXPERIMENTAL)
-CONFIG_BLK_DEV_OPTI621
- This is a driver for the OPTi 82C621 EIDE controller.
- Please read the comments at the top of drivers/block/opti621.c.
+ Please read the comments at the top of drivers/block/alim15x3.c
-NS87415 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_NS87415
- This driver adds detection and support for the NS87415 chip
- (used in SPARC64, among others).
+ If unsure, say N.
- Please read the comments at the top of drivers/block/ns87415.c.
+CMD646 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_CMD646
+ Say Y here if you have an IDE controller which uses this chipset.
CY82C693 chipset support (EXPERIMENTAL)
CONFIG_BLK_DEV_CY82C693
If you say Y here, you need to say Y to "Use DMA by default
when available" as well.
-VIA82C586 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_VIA82C586
- Saying Y here 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. To use some features of this chipset, you
- will have to issue a kernel command line as described in the file
- drivers/block/via82c586.c. Furthermore, if you also say Y to "/proc
- filesystem support" and set DISPLAY_APOLLO_TIMINGS in via82c586.c,
- you will be able to read information about the IDE controller from
- the virtual file /proc/ide/via.
+HPT34X chipset support
+CONFIG_BLK_DEV_HPT34X
+ This driver adds up to 4 more EIDE devices sharing a single
+ interrupt. The HPT343 chipset in its current form is a non-bootable
+ controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
+ PCI UDMA controllers. This driver requires dynamic tuning of the
+ chipset during the ide-probe at boot time. It is reported to support
+ DVD II drives, by the manufacturer.
- If you say Y here, you also need to say Y to "Use DMA by default
- when available", above.
+HPT34X DMA support (EXPERIMENTAL)
+CONFIG_BLK_DEV_HPT34X_DMA
+ you need to say Y to "Use DMA by default when available" if you say
+ Y here.
+
+ Please read the comments at the top of drivers/block/hpt34x.c
+
+HPT366 chipset support
+CONFIG_BLK_DEV_HPT366
+ This is an Ultra DMA chipset for ATA-66.
+
+ This driver adds up to 4 more EIDE devices sharing a single
+ interrupt. The HPT366 chipset in its current form is a non-bootable.
+ 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.
+
+ Please read the comments at the top of drivers/block/hpt366.c
+
+HPT366 (EXPERIMENTAL)
+CONFIG_BLK_DEV_HPT366_SHARED
+ This requires CONFIG_BLK_DEV_HPT366.
+ It appears that there are different versions or releases of this hardware
+ by ABit. Since some cases the second channel of the onboard chipset works
+ and others fail, it is default disabled. This is required to be set if you
+ want to attempt the setup of the second channel.
+
+ JUMBO WARNING, do not boot a kernel with this enabled if it is your only
+ one. You may not be able to get back into your machine without physically
+ detaching the attached devices.
If unsure, say N.
-CMD646 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_CMD646
- Say Y here if you have an IDE controller which uses this chipset.
+NS87415 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_NS87415
+ This driver adds detection and support for the NS87415 chip
+ (used in SPARC64, among others).
-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.
+ Please read the comments at the top of drivers/block/ns87415.c.
- If you say Y here, you also need to say Y to "Use DMA by default
- when available", above.
+OPTi 82C621 enhanced support (EXPERIMENTAL)
+CONFIG_BLK_DEV_OPTI621
+ This is a driver for the OPTi 82C621 EIDE controller.
+ Please read the comments at the top of drivers/block/opti621.c.
- Please read the comments at the top of drivers/block/alim15x3.c
+Intel PIIXn chipsets support
+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.
+
+PIIXn Tuning support
+CONFIG_BLK_DEV_PIIX_TUNING
+ This driver extension adds DMA mode setting and tuning for all PIIX
+ IDE controllers by Intel. Since the BIOS can sometimes improperly
+ set up the device/adapter combination and speed limits, it has
+ become a necessity to back/forward speed devices as needed.
+
+ Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
+ 2 if the BIOS can not perform this task at initialization.
If unsure, say N.
If unsure, say N.
-Special UDMA Feature (EXPERIMENTAL)
+Special UDMA Feature
PDC202XX_FORCE_BURST_BIT
For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally
for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
If unsure, say N.
-Special Mode Feature (DANGEROUS)
+Special Mode Feature (EXPERIMENTAL)
PDC202XX_FORCE_MASTER_MODE
For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for
possible Hardware RAID 0,1 for the FastTrak Series.
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 say Y here, and preferably also to "Use DMA by default when
- available".
+Winbond SL82c105 support
+CONFIG_BLK_DEV_SL82C105
+ If you have a Winbond SL82c105 IDE controller, say Y here to enable
+ special configuration for this chip. This is common on various CHRP
+ motherboards, but could be used elsewhere. If in doubt, say Y.
- Please read the comments at the top of drivers/block/aec6210.c
+Tekram TRM290 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_TRM290
+ This driver adds support for bus master DMA transfers
+ using the Tekram TRM290 PCI IDE chip. Volunteers are
+ needed for further tweaking and development.
+ Please read the comments at the top of drivers/block/trm290.c.
-HPT366 chipset support
-CONFIG_BLK_DEV_HPT366
- This is an Ultra DMA chipset for ATA-66.
-
- This driver adds up to 4 more EIDE devices sharing a single
- interrupt. The HPT366 chipset in its current form is a non-bootable.
- 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.
-
-Intel PIIXn chipsets support
-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'.
+VIA82CXXX chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_VIA82CXXX
+ 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.
+ Please read the comments at the top of drivers/block/via82cxxx.c
- Please read the comments at the top of drivers/block/piix.c
+ If you say Y here, you also need to say Y to "Use DMA by default
+ when available", above.
If unsure, say N.
-PIIXn Tuning support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PIIX_TUNING
- This driver extension adds DMA mode setting and tuning for all PIIX
- IDE controllers by Intel. Since the BIOS can sometimes improperly
- set up the device/adapter combination and speed limits, it has
- become a necessity to back/forward speed devices as needed.
+Other IDE chipset support
+CONFIG_IDE_CHIPSETS
+ Say Y here if you want to include enhanced support for various IDE
+ interface chipsets used on motherboards and add-on cards. You can
+ then pick your particular IDE chip from among the following options.
+ This enhanced support may be necessary for Linux to be able to
+ access the 3rd/4th drives in some systems. It may also enable
+ setting of higher speed I/O rates to improve system performance with
+ these chipsets. Most of these also require special kernel boot
+ parameters to actually turn on the support at runtime; you can find
+ a list of these in the file Documentation/ide.txt.
+
+ People with SCSI-only systems can say N here.
- Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
- 2 if the BIOS can not perform this task at initialization.
+Generic 4 drives/port support
+CONFIG_BLK_DEV_4DRIVES
+ Certain older chipsets, including the Tekram 690CD, use a single set
+ of I/O ports at 0x1f0 to control up to four drives, instead of the
+ customary two drives per port. Support for this can be enabled at
+ runtime using the "ide0=four" kernel boot parameter if you say Y
+ here.
- If unsure, say N.
+ALI M14xx support
+CONFIG_BLK_DEV_ALI14XX
+ This driver is enabled at runtime using the "ide0=ali14xx" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
+ I/O speeds to be set as well. See the files Documentation/ide.txt
+ and drivers/block/ali14xx.c for more info.
-HPT34X chipset support
-CONFIG_BLK_DEV_HPT34X
- This driver adds up to 4 more EIDE devices sharing a single
- interrupt. The HPT343 chipset in its current form is a non-bootable
- controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
- PCI UDMA controllers. This driver requires dynamic tuning of the
- chipset during the ide-probe at boot time. It is reported to support
- DVD II drives, by the manufacturer.
+DTC-2278 support
+CONFIG_BLK_DEV_DTC2278
+ This driver is enabled at runtime using the "ide0=dtc2278" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the DTC-2278 card, and permits faster I/O speeds to be set as
+ well. See the Documentation/ide.txt and drivers/block/dtc2278.c
+ files for more info.
-HPT34X DMA support (DANGEROUS)
-CONFIG_BLK_DEV_HPT34X_DMA
- you need to say Y to "Use DMA by default when available" if you say
- Y here.
+Holtek HT6560B support
+CONFIG_BLK_DEV_HT6560B
+ This driver is enabled at runtime using the "ide0=ht6560b" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the Holtek card, and permits faster I/O speeds to be set as well.
+ See the Documentation/ide.txt and drivers/block/ht6560b.c files for
+ more info.
- Please read the comments at the top of drivers/block/hpt343.c
+PROMISE DC4030 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PDC4030
+ This driver provides support for the secondary IDE interface and
+ cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
+ is known to incur timeouts/retries during heavy I/O to drives
+ attached to the secondary interface. CDROM and TAPE devices are not
+ supported yet. This driver is enabled at runtime using the
+ "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
+ and drivers/block/pdc4030.c files for more info.
QDI QD6580 support
CONFIG_BLK_DEV_QD6580
See the files Documentation/ide.txt and drivers/block/umc8672.c for
more info.
-ALI M14xx support
-CONFIG_BLK_DEV_ALI14XX
- This driver is enabled at runtime using the "ide0=ali14xx" kernel
- boot parameter. It enables support for the secondary IDE interface
- of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
- I/O speeds to be set as well. See the files Documentation/ide.txt
- and drivers/block/ali14xx.c for more info.
+PS/2 ESDI hard disk support
+CONFIG_BLK_DEV_PS2
+ Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
+ hard disk.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called ps2esdi.o.
Amiga builtin Gayle IDE interface support
CONFIG_BLK_DEV_GAYLE
--- /dev/null
+Started Oct 1999 by Kanoj Sarcar <kanoj@sgi.com>
+
+The intent of this file is to have an uptodate, running commentary
+from different people about how locking and synchronization is done
+in the Linux vm code.
+
+vmlist_access_lock/vmlist_modify_lock
+--------------------------------------
+
+Page stealers pick processes out of the process pool and scan for
+the best process to steal pages from. To guarantee the existance
+of the victim mm, a mm_count inc and a mmdrop are done in swap_out().
+Page stealers hold kernel_lock to protect against a bunch of races.
+The vma list of the victim mm is also scanned by the stealer,
+and the vmlist_lock is used to preserve list sanity against the
+process adding/deleting to the list. This also gurantees existance
+of the vma. Vma existance gurantee while invoking the driver
+swapout() method in try_to_swap_out() also relies on the fact
+that do_munmap() temporarily gets lock_kernel before decimating
+the vma, thus the swapout() method must snapshot all the vma
+fields it needs before going to sleep (which will release the
+lock_kernel held by the page stealer). Currently, filemap_swapout
+is the only method that depends on this shaky interlocking.
+
+Any code that modifies the vmlist, or the vm_start/vm_end/
+vm_flags:VM_LOCKED/vm_next of any vma *in the list* must prevent
+kswapd from looking at the chain. This does not include driver mmap()
+methods, for example, since the vma is still not in the list.
+
+The rules are:
+1. To modify the vmlist (add/delete or change fields in an element),
+you must hold mmap_sem to guard against clones doing mmap/munmap/faults,
+(ie all vm system calls and faults), and from ptrace, swapin due to
+swap deletion etc.
+2. To modify the vmlist (add/delete or change fields in an element),
+you must also hold vmlist_modify_lock, to guard against page stealers
+scanning the list.
+3. To scan the vmlist (find_vma()), you must either
+ a. grab mmap_sem, which should be done by all cases except
+ page stealer.
+or
+ b. grab vmlist_access_lock, only done by page stealer.
+4. While holding the vmlist_modify_lock, you must be able to guarantee
+that no code path will lead to page stealing. A better guarantee is
+to claim non sleepability, which ensures that you are not sleeping
+for a lock, whose holder might in turn be doing page stealing.
+5. You must be able to guarantee that while holding vmlist_modify_lock
+or vmlist_access_lock of mm A, you will not try to get either lock
+for mm B.
+
+The caveats are:
+1. find_vma() makes use of, and updates, the mmap_cache pointer hint.
+The update of mmap_cache is racy (page stealer can race with other code
+that invokes find_vma with mmap_sem held), but that is okay, since it
+is a hint. This can be fixed, if desired, by having find_vma grab the
+vmlist lock.
+
+
+Code that add/delete elements from the vmlist chain are
+1. callers of insert_vm_struct
+2. callers of merge_segments
+3. callers of avl_remove
+
+Code that changes vm_start/vm_end/vm_flags:VM_LOCKED of vma's on
+the list:
+1. expand_stack
+2. mprotect
+3. mlock
+4. mremap
+
+It is advisable that changes to vm_start/vm_end be protected, although
+in some cases it is not really needed. Eg, vm_start is modified by
+expand_stack(), it is hard to come up with a destructive scenario without
+having the vmlist protection in this case.
+
+The vmlist lock nests with the inode i_shared_lock and the kmem cache
+c_spinlock spinlocks. This is okay, since code that holds i_shared_lock
+never asks for memory, and the kmem code asks for pages after dropping
+c_spinlock.
+
+The vmlist lock can be a sleeping or spin lock. In either case, care
+must be taken that it is not held on entry to the driver methods, since
+those methods might sleep or ask for memory, causing deadlocks.
+
+The current implementation of the vmlist lock uses the page_table_lock,
+which is also the spinlock that page stealers use to protect changes to
+the victim process' ptes. Thus we have a reduction in the total number
+of locks.
W: http://mosquitonet.Stanford.EDU/strip.html
S: Unsupported ?
+SUPERH
+P: Niibe Yutaka
+M: gniibe@chroot.org
+P: Kazumoto Kojima
+M: kkojima@rr.iij4u.or.jp
+L: linux-sh@m17n.org
+W: http://www.m17n.org/linux-sh/
+W: http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html
+S: Maintained
+
SVGA HANDLING
P: Martin Mares
M: mj@atrey.karlin.mff.cuni.cz
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_CMD646 is not set
CONFIG_BLK_DEV_SL82C105=y
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_CMD646 is not set
CONFIG_BLK_DEV_SL82C105=y
# CONFIG_IDE_CHIPSETS is not set
vmlinux: arch/i386/vmlinux.lds
-arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE
- $(CPP) -C -P -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds
-
FORCE: ;
.PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
@$(MAKEBOOT) clean
archmrproper:
- rm -f arch/i386/vmlinux.lds
archdep:
@$(MAKEBOOT) dep
define_bool CONFIG_X86_USE_3DNOW y
fi
-choice 'Maximum Physical Memory' \
- "1GB CONFIG_1GB \
- 2GB CONFIG_2GB" 1GB
-
bool 'Math emulation' CONFIG_MATH_EMULATION
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
bool 'Symmetric multi-processing support' CONFIG_SMP
mainmenu_option next_comment
comment 'General setup'
-bool 'BIGMEM support' CONFIG_BIGMEM
+bool 'Support for over 1Gig of memory' CONFIG_BIGMEM
bool 'Networking support' CONFIG_NET
bool 'SGI Visual Workstation support' CONFIG_VISWS
if [ "$CONFIG_VISWS" = "y" ]; then
#include <asm/smp.h>
#include <asm/lithium.h>
+#include <asm/io.h>
#include "pci-i386.h"
#include <asm/cobalt.h>
-#include "irq.h"
+#include <linux/irq.h>
/*
* This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
--- /dev/null
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0xC0000000 + 0x100000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.gnu.warning)
+ } = 0x9090
+ .text.lock : { *(.text.lock) } /* out-of-line lock text */
+ .rodata : { *(.rodata) }
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ _etext = .; /* End of text section */
+
+ .data : { /* Data */
+ *(.data)
+ CONSTRUCTORS
+ }
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(8192); /* init_task */
+ .data.init_task : { *(.data.init_task) }
+
+ . = ALIGN(4096); /* Init code and data */
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+ . = ALIGN(4096);
+ __init_end = .;
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
+ _end = . ;
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+}
+++ /dev/null
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-SECTIONS
-{
- . = PAGE_OFFSET_RAW + 0x100000;
- _text = .; /* Text and read-only data */
- .text : {
- *(.text)
- *(.fixup)
- *(.gnu.warning)
- } = 0x9090
- .text.lock : { *(.text.lock) } /* out-of-line lock text */
- .rodata : { *(.rodata) }
- .kstrtab : { *(.kstrtab) }
-
- . = ALIGN(16); /* Exception table */
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
-
- __start___ksymtab = .; /* Kernel symbol table */
- __ksymtab : { *(__ksymtab) }
- __stop___ksymtab = .;
-
- _etext = .; /* End of text section */
-
- .data : { /* Data */
- *(.data)
- CONSTRUCTORS
- }
-
- _edata = .; /* End of data section */
-
- . = ALIGN(8192); /* init_task */
- .data.init_task : { *(.data.init_task) }
-
- . = ALIGN(4096); /* Init code and data */
- __init_begin = .;
- .text.init : { *(.text.init) }
- .data.init : { *(.data.init) }
- . = ALIGN(16);
- __setup_start = .;
- .setup.init : { *(.setup.init) }
- __setup_end = .;
- __initcall_start = .;
- .initcall.init : { *(.initcall.init) }
- __initcall_end = .;
- . = ALIGN(4096);
- __init_end = .;
-
- . = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
-
- . = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
- __bss_start = .; /* BSS */
- .bss : {
- *(.bss)
- }
- _end = . ;
-
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
-}
#include <asm/hydra.h>
#include <asm/prom.h>
#include <asm/gg2.h>
-#include <asm/ide.h>
#include <asm/machdep.h>
#include "pci.h"
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/blk.h>
+#include <linux/ide.h>
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/pci.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <linux/ide.h>
-#include <asm/ide.h>
#include <asm/prom.h>
#include <asm/gg2.h>
#include <asm/pci-bridge.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/blk.h>
+#include <linux/ide.h>
#include <linux/ioport.h>
#include <asm/mmu.h>
#include <asm/residual.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/ide.h>
#include <asm/mbx.h>
#include <asm/machdep.h>
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/blk.h>
+#include <linux/ide.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
#include <linux/ide.h>
#include <asm/ohare.h>
#include <asm/mediabay.h>
#include <asm/feature.h>
-#include <asm/ide.h>
#include <asm/machdep.h>
#include <asm/keyboard.h>
#include <asm/dma.h>
#if defined(CONFIG_BLK_DEV_IDE) && defined(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, 88, 89 };
+static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 };
kdev_t __init find_ide_boot(void)
{
#include <asm/residual.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/ide.h>
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/machdep.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/blk.h>
+#include <linux/ide.h>
#include <asm/init.h>
#include <asm/residual.h>
#include <asm/io.h>
-#include <linux/ide.h>
-#include <asm/ide.h>
#include <asm/prom.h>
#include <asm/processor.h>
#include <asm/pgtable.h>
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_CMD646 is not set
CONFIG_BLK_DEV_SL82C105=y
# CONFIG_IDE_CHIPSETS is not set
-# $Id$
+# $Id: Makefile,v 1.1 1999/09/18 16:55:51 gniibe Exp gniibe $
#
# 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.
#
+# Copyright (C) 1999 Kaz Kojima
+#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
# for "archclean" and "archdep" for cleaning up and making dependencies for
#
# Select the object file format to substitute into the linker script.
#
-tool-prefix = sh-gniibe-
-oformat = elf
+tool-prefix = sh-elf
+
+ifdef CONFIG_LITTLE_ENDIAN
+CFLAGS += -ml
+AFLAGS += -ml
+# LINKFLAGS += -EL
+LDFLAGS := -EL
+
+LD =$(CROSS_COMPILE)ld $(LDFLAGS)
+
+endif
ifdef CONFIG_CROSSCOMPILE
CROSS_COMPILE = $(tool-prefix)
endif
-LINKFLAGS = # -EL # -static #-N
MODFLAGS +=
#
#
-CFLAGS += -m3 # -ml
-LINKFLAGS +=
-LDFLAGS += # -EL
-#
-#
-HOSTCC = cc
+ifdef CONFIG_CPU_SH3
+CFLAGS += -m3
+AFLAGS += -m3
+endif
+ifdef CONFIG_CPU_SH4
+CFLAGS += -m4
+AFLAGS += -m4
+endif
#
# Choosing incompatible machines durings configuration will result in
SUBDIRS := $(SUBDIRS) $(addprefix arch/sh/, kernel mm lib)
CORE_FILES := arch/sh/kernel/kernel.o arch/sh/mm/mm.o $(CORE_FILES)
-LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a /home/niibe/lib/gcc-lib/sh-gniibe-elf/egcs-2.91.66/libgcc.a
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a \
+ $(LIBGCC)
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
vmlinux: arch/sh/vmlinux.lds
arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE
- gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/linux/config.h -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
+ gcc -E -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
FORCE: ;
# $(MAKE) -C arch/$(ARCH)/tools clean
archmrproper:
+ rm -f arch/sh/vmlinux.lds
archdep:
@$(MAKEBOOT) dep
mainmenu_option next_comment
comment 'Processor type and features'
choice 'Processor family' \
- "SH3 CONFIG_CPU_SH3 \
- SH4 CONFIG_CPU_SH4" SH3
+ "SH-3 CONFIG_CPU_SH3 \
+ SH-4 CONFIG_CPU_SH4" SH-3
bool 'Little Endian' CONFIG_LITTLE_ENDIAN
-hex 'Physical memory start address' CONFIG_MEMORY_START 0c000000
+hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+bool 'Use SH CPU internal real time clock' CONFIG_SH_CPU_RTC
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
- bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool ' Kernel module loader' CONFIG_KMOD
+ bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
-define_bool CONFIG_SERIAL n
-define_bool CONFIG_SH3SCI_SERIAL y
-define_bool CONFIG_SERIAL_CONSOLE y
-
mainmenu_option next_comment
-comment 'Floppy, IDE, and other block devices'
-
+comment 'General setup'
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+endmenu
+
+mainmenu_option next_comment
+comment 'Character devices'
+define_bool CONFIG_SERIAL n
+define_bool CONFIG_SERIAL_CONSOLE y
+bool 'SuperH SCI support' CONFIG_SH_SCI_SERIAL
+bool 'SuperH SCIF support' CONFIG_SH_SCIF_SERIAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Floppy, IDE, and other block devices'
tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
comment 'Kernel hacking'
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'GDB Stub kernel debug' CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
endmenu
#
# Processor type and features
#
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-# CONFIG_LITTLE_ENDIAN is not set
-CONFIG_MEMORY_START=0c000000
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+CONFIG_LITTLE_ENDIAN=y
+CONFIG_MEMORY_START=08000000
#
# Loadable module support
#
# CONFIG_MODULES is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH3SCI_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
#
-# Floppy, IDE, and other block devices
+# General setup
#
# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
+# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
#
-# Networking options
+# Character devices
#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
-# CONFIG_FILTER is not set
-# CONFIG_UNIX is not set
-# CONFIG_INET is not set
+# CONFIG_SERIAL is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SH_SCI_SERIAL is not set
+CONFIG_SH_SCIF_SERIAL=y
#
-#
+# Floppy, IDE, and other block devices
#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
#
# Unix 98 PTY support
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
+# CONFIG_UDF_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-#
-# Network File Systems
-#
-
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMD_DISKLABEL is not set
-# CONFIG_SGI_DISKLABEL is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
# Kernel hacking
#
# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL_WITH_GDB_STUB=y
O_TARGET := kernel.o
O_OBJS := process.o signal.o entry.o traps.o irq.o irq_onchip.o \
- ptrace.o setup.o time.o sys_sh.o test-img.o semaphore.o
+ ptrace.o setup.o time.o sys_sh.o semaphore.o
OX_OBJS := sh_ksyms.o
MX_OBJS :=
-/* $Id$
+/* $Id: entry.S,v 1.15 1999/10/17 01:32:52 gniibe Exp $
*
* linux/arch/sh/entry.S
*
#include <linux/sys.h>
#include <linux/linkage.h>
+#include <linux/config.h>
! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
* Stack layout in 'ret_from_syscall':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
- * updated in process.c:copy_thread, signal.c:do_signal,
- * ptrace.c and ptrace.h
+ * updated in ptrace.c and ptrace.h
*
- * syscall #
+ * syscall #
+ * ssr
+ * r15 = stack pointer
* r0
* ...
- * r15
+ * r14
* gbr
* mach
* macl
* pr
- * ssr
* spc
*
*/
ENOSYS = 38
-TRA = 0xffffffd0
-EXPEVT = 0xffffffd4
-INTEVT = 0xffffffd8
+#if defined(__sh3__)
+TRA = 0xffffffd0
+EXPEVT = 0xffffffd4
+INTEVT = 0xffffffd8
+MMU_TEA = 0xfffffffc ! TLB Exception Address Register
+#elif defined(__SH4__)
+TRA = 0xff000020
+EXPEVT = 0xff000024
+INTEVT = 0xff000028
+MMU_TEA = 0xff00000c ! TLB Exception Address Register
+#endif
/* Offsets to the stack */
SYSCALL_NR = 0
-R0 = 4
-R15 = 64
+SR = 4
+SP = 8
+R0 = 12
#define k0 r0
#define k1 r1
! Although this could be written in assembly language (and it'd be faster),
! this first version depends *much* on C implementation.
!
-MMU_TEA = 0xfffffffc ! TLB Exception Address Register
-#define DO_FAULT(write) \
- mov #MMU_TEA,r0; \
- mov.l @r0,r6; \
- /* STI */ \
- mov.l 3f,r1; \
- stc sr,r0; \
- and r1,r0; \
- ldc r0,sr; \
- /* */ \
- mov r15,r4; \
- mov.l 2f,r0; \
- jmp @r0; \
+#define DO_FAULT(write) \
+ mov.l 4f,r0; \
+ mov.l @r0,r6; \
+ /* STI */ \
+ mov.l 3f,r1; \
+ stc sr,r0; \
+ and r1,r0; \
+ ldc r0,sr; \
+ /* */ \
+ mov r15,r4; \
+ mov.l 2f,r0; \
+ jmp @r0; \
mov #write,r5;
.balign 4
.balign 4
2: .long SYMBOL_NAME(do_page_fault)
3: .long 0xefffffff ! BL=0
+4: .long MMU_TEA
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+ .balign 4
+ /* Unwind the stack and jmp to the debug entry */
+debug:
+ add #4,r15 ! skip syscall number
+ ldc.l @r15+,ssr
+ mov.l @r15+,r10 ! original stack
+ mov.l @r15+,r0
+ mov.l @r15+,r1
+ mov.l @r15+,r2
+ mov.l @r15+,r3
+ mov.l @r15+,r4
+ mov.l @r15+,r5
+ mov.l @r15+,r6
+ mov.l @r15+,r7
+ stc sr,r14
+ mov.l 8f,r9 ! BL =1, RB=1
+ or r9,r14
+ ldc r14,sr ! here, change the register bank
+ mov r10,k0
+ mov.l @r15+,r8
+ mov.l @r15+,r9
+ mov.l @r15+,r10
+ mov.l @r15+,r11
+ mov.l @r15+,r12
+ mov.l @r15+,r13
+ mov.l @r15+,r14
+ ldc.l @r15+,gbr
+ lds.l @r15+,mach
+ lds.l @r15+,macl
+ lds.l @r15+,pr
+ ldc.l @r15+,spc
+ mov k0,r15
+ !
+ mov.l 9f,k0
+ jmp @k0
+ nop
+ .balign 4
+8: .long 0x300000f0
+9: .long 0xa0000100
+#endif
.balign 4
-error: mov #-1,r0
+error:
! STI
mov.l 2f,r1
stc sr,r0
and r1,r0
ldc r0,sr
!
- mov.l r0,@r15 ! syscall nr = -1
mov.l 1f,r1
+ mov #-1,r0
jmp @r1
- nop
+ mov.l r0,@r15 ! syscall nr = -1
.balign 4
1: .long SYMBOL_NAME(do_exception_error)
+2: .long 0xefffffff ! BL=0
reschedule:
mova SYMBOL_NAME(ret_from_syscall),r0
1: .long SYMBOL_NAME(schedule)
badsys: mov #-ENOSYS,r0
- bra SYMBOL_NAME(ret_from_syscall)
+ rts ! go to ret_from_syscall..
mov.l r0,@(R0,r15)
signal_return:
! We can reach here from an interrupt handler,
! so, we need to unblock interrupt.
+ /* STI */
mov.l 1f,r1
stc sr,r0
and r1,r0
!
ENTRY(ret_from_fork)
bra SYMBOL_NAME(ret_from_syscall)
- add #4,r15 ! pop down bogus r0
+ add #4,r15 ! pop down bogus r0 (see switch_to MACRO)
!
! The immediate value of "trapa" indicates the number of arguments
! placed on the stack.
!
+! Note that TRA register contains the value = Imm x 4.
+!
system_call:
- mov #TRA,r2
+ mov.l 1f,r2
mov.l @r2,r8
+ !
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+ mov #0x20,r1
+ extu.b r1,r1
+ shll2 r1
+ cmp/hs r1,r8
+ bt debug
+#endif
! STI
mov.l 2f,r1
stc sr,r2
!
mov.l __n_sys,r1
cmp/ge r1,r0
- bt badsys
+ bt/s badsys
+ mov r0,r2
!
stc ksp,r1 !
mov.l __tsk_flags,r0 !
add r0,r1 !
mov.l @r1,r0 ! Is it trace?
tst #PF_TRACESYS,r0
- bt 6f
+ bt 5f
! Trace system call
mov #-ENOSYS,r1
mov.l r1,@(R0,r15)
jsr @r1
nop
mova 4f,r0
- bra 7f
+ bra 6f
lds r0,pr
!
-6: mova 1f,r0
+5: mova ret,r0 ! normal case
lds r0,pr
! Build the stack frame if TRA > 0
-7: cmp/pl r8
+ !
+6: mov r2,r3
+ mov r8,r2
+ cmp/pl r8
bf 9f
- shll2 r8 ! x4
- mov #R15,r0
- mov.l @(r0,r15),r0 ! get original stack
-8: add #-4,r8
- mov.l @(r0,r8),r1
+ mov.l @(SP,r15),r0 ! get original stack
+7: add #-4,r8
+8: mov.l @(r0,r8),r1 ! May cause address error exception..
mov.l r1,@-r15
cmp/pl r8
- bt 8b
+ bt 7b
!
-9: mov.l @(SYSCALL_NR,r15),r0
+9: mov r3,r0
shll2 r0 ! x4
mov.l __sct,r1
add r1,r0
mov.l @r0,r1
jmp @r1
- nop
+ mov r2,r8
+
+ ! In case of trace
.balign 4
-4: mov.l r0,@(R0,r15) ! save the return value
+4: add r8,r15 ! pop off the arguments
+ mov.l r0,@(R0,r15) ! save the return value
mov.l 3f,r1
mova SYMBOL_NAME(ret_from_syscall),r0
jmp @r1
.balign 4
3: .long SYMBOL_NAME(syscall_trace)
2: .long 0xefffffff ! BL=0
-1: mov.l r0,@(R0,r15) ! save the return value
+1: .long TRA
+
+ .section .fixup,"ax"
+fixup_syscall_argerr:
+ rts
+ mov.l 1f,r0
+1: .long -22 ! -EINVAL
+.previous
+
+ .section __ex_table, "a"
+ .balign 4
+ .long 8b,fixup_syscall_argerr
+.previous
+
+
+ENTRY(ret_from_irq)
+ mov.l @(SR,r15),r0 ! get original stack
+ shll r0
+ shll r0 ! kernel space?
+ bt restore_all ! Yes, it's from kernel, go back soon
+ ! XXX: Is it better to run through bottom half?
+ ! In such a case, we should go "ret_from_syscall" instead
+ bra ret_with_reschedule
+ nop
+
+ret: add r8,r15 ! pop off the arguments
+ mov.l r0,@(R0,r15) ! save the return value
/* fall through */
ENTRY(ret_from_syscall)
-ENTRY(ret_from_irq)
mov.l __bh_mask,r0
mov.l @r0,r1
mov.l __bh_active,r0
tst #0xff,r0
bf signal_return
!
- .balign 4
restore_all:
add #4,r15 ! skip syscall number
+ ldc.l @r15+,ssr
+ mov.l @r15+,r10 ! original stack
mov.l @r15+,r0
mov.l @r15+,r1
mov.l @r15+,r2
mov.l __blrb_flags,r9 ! BL =1, RB=1
or r9,r14
ldc r14,sr ! here, change the register bank
+ mov r10,k0
mov.l @r15+,r8
mov.l @r15+,r9
mov.l @r15+,r10
mov.l @r15+,r12
mov.l @r15+,r13
mov.l @r15+,r14
- mov.l @r15+,k0
ldc.l @r15+,gbr
lds.l @r15+,mach
lds.l @r15+,macl
lds.l @r15+,pr
- ldc.l @r15+,ssr
ldc.l @r15+,spc
mov k0,r15
rte
!
.balign 256,0,256
general_exception:
- mov #EXPEVT,k2
+ mov.l 1f,k2
mov.l 2f,k3
bra handle_exception
mov.l @k2,k2
.balign 4
2: .long SYMBOL_NAME(ret_from_syscall)
+1: .long EXPEVT
!
!
.balign 1024,0,1024
tlb_miss:
- mov #EXPEVT,k2
+ mov.l 1f,k2
mov.l 3f,k3
bra handle_exception
mov.l @k2,k2
!
.balign 512,0,512
interrupt:
- mov #INTEVT,k2
+ mov.l 2f,k2
mov.l 4f,k3
bra handle_exception
mov.l @k2,k2
.balign 4
+1: .long EXPEVT
+2: .long INTEVT
3: .long SYMBOL_NAME(ret_from_syscall)
4: .long SYMBOL_NAME(ret_from_irq)
! Using k0, k1 for scratch registers (r0_bank1, and r1_bank1),
! save all registers onto stack.
!
- mov.l 2f,k1
stc ssr,k0 ! from kernel space?
shll k0 ! Check MD bit (bit30)
shll k0
bt/s 1f ! it's from kernel to kernel transition
mov r15,k0 ! save original stack to k0 anyway
mov kernel_sp,r15 ! change to kernel stack
-1: stc.l spc,@-r15 ! save control registers
- stc.l ssr,@-r15
+1: stc.l spc,@-r15
sts.l pr,@-r15
!
lds k3,pr ! Set the return address to pr
sts.l macl,@-r15
sts.l mach,@-r15
stc.l gbr,@-r15
- mov.l k0,@-r15 ! save orignal stack, and general registers
mov.l r14,@-r15
!
+ mov.l 2f,k1
stc sr,r14 ! back to normal register bank, and
and k1,r14 ! ..
ldc r14,sr ! ...changed here.
mov.l r2,@-r15
mov.l r1,@-r15
mov.l r0,@-r15
+ stc.l r0_bank,@-r15 ! save orignal stack
+ stc.l ssr,@-r15
mov.l r0,@-r15 ! push r0 again (for syscall number)
! Then, dispatch to the handler, according to the excepiton code.
stc k_ex_code,r1
1: .long SYMBOL_NAME(exception_handling_table)
2: .long 0xdfffffff ! RB=0, BL=1
+none:
+ rts
+ nop
+
.data
ENTRY(exception_handling_table)
- .long 0
- .long 0
+ .long none /* XXX: Avoid spurious interrupt */
+ .long error
.long tlb_miss_load
.long tlb_miss_store
.long initial_page_write
.long tlb_protection_violation_store
.long error ! address_error_load (filled by trap_init)
.long error ! address_error_store (filled by trap_init)
- .long 0
- .long 0
+ .long error ! fpu_exception
+ .long error
.long system_call ! Unconditional Trap
.long error ! reserved_instruction (filled by trap_init)
.long error ! illegal_slot_instruction (filled by trap_init)
ENTRY(nmi_slot)
- .long error ! Not implemented yet
+ .long none ! Not implemented yet
ENTRY(user_break_point_trap)
.long error ! Not implemented yet
ENTRY(interrupt_table)
.long SYMBOL_NAME(do_IRQ) ! 1100
.long SYMBOL_NAME(do_IRQ) ! 1101
.long SYMBOL_NAME(do_IRQ) ! 1110
- .long 0
+ .long error
! Internal hardware
.long SYMBOL_NAME(do_IRQ) ! TMU0 tuni0
.long SYMBOL_NAME(do_IRQ) ! TMU1 tuni1
.long SYMBOL_NAME(do_IRQ) ! rovi
.long SYMBOL_NAME(do_IRQ)
.long SYMBOL_NAME(do_IRQ)
+ .long SYMBOL_NAME(do_IRQ) ! Hitachi UDI
+ .long SYMBOL_NAME(do_IRQ) ! GPIO
+ .long SYMBOL_NAME(do_IRQ) ! DMAC dmte0
+ .long SYMBOL_NAME(do_IRQ) ! dmte1
+ .long SYMBOL_NAME(do_IRQ) ! dmte2
+ .long SYMBOL_NAME(do_IRQ) ! dmte3
+ .long SYMBOL_NAME(do_IRQ) ! dmae
.long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ)
+ .long SYMBOL_NAME(do_IRQ) ! SCIF eri
+ .long SYMBOL_NAME(do_IRQ) ! rxi
+ .long SYMBOL_NAME(do_IRQ) ! bri
+ .long SYMBOL_NAME(do_IRQ) ! txi
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error ! fpu
+ .long error ! fpu
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
.long SYMBOL_NAME(sys_swapon)
.long SYMBOL_NAME(sys_reboot)
.long SYMBOL_NAME(old_readdir)
- .long SYMBOL_NAME(sys_ni_syscall) /* old_mmap */ /* 90 */
+ .long SYMBOL_NAME(sys_mmap) /* 90 */
.long SYMBOL_NAME(sys_munmap)
.long SYMBOL_NAME(sys_truncate)
.long SYMBOL_NAME(sys_ftruncate)
-/* $Id$
+/* $Id: head.S,v 1.6 1999/10/05 12:34:16 gniibe Exp $
*
* arch/sh/kernel/head.S
*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999 Niibe Yutaka & Kaz Kojima
*
* 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
*
* Head.S contains the SH exception handlers and startup code.
*/
-#include <linux/config.h>
-#include <linux/threads.h>
#include <linux/linkage.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#ifdef CONFIG_CPU_SH3
-/* Following values are assumed to be as small as immediate. */
-#define CCR 0xffffffec /* Address of Cache Control Register */
-#define CACHE_INIT 0x00000009 /* 8k-byte cache, flush, enable */
-#elif CONFIG_CPU_SH4
-/* Should fill here. */
-#endif
+ .section .empty_zero_page, "aw"
+ENTRY(empty_zero_page)
+ .long 1 /* MOUNT_ROOT_RDONLY */
+ .long 0 /* RAMDISK_FLAGS */
+ .long 0x0200 /* ORIG_ROOT_DEV */
+ .long 1 /* LOADER_TYPE */
+ .long 0x88400000 /* INITRD_START */
+ .long 0x00400000 /* INITRD_SIZE */
+ .long 0x89000000 /* MEMORY_END */
+ .long 0
+ .text
+ .balign 4096,0,4096
+/*
+ * Condition at the entry of _stext:
+ *
+ * BSC has already been initialized.
+ * INTC may or may not be initialized.
+ * VBR may or may not be initialized.
+ * MMU may or may not be initialized.
+ * Cache may or may not be initialized.
+ * Hardware (including on-chip modules) may or may not be initialized.
+ *
+ * The register R4&R5 holds the address of the parameter block, which has
+ * command-line data, etc.
+ *
+ */
ENTRY(_stext)
- ! Switch to register bank 0
- stc sr,r1 !
- mov.l 1f,r0 ! RB=0, BL=1
- and r1,r0
- ldc r0,sr
- ! Enable cache
-#ifdef CONFIG_CPU_SH3
- mov #CCR,r1
- mov.l @r1,r0
- cmp/eq #1,r0 ! If it's enabled already, don't flush it
- bt/s 8f
- mov #CACHE_INIT,r0
- mov.l r0,@r1
-#elif CONFIG_CPU_SH4
- ! Should fill here.
+#if defined(__SH4__)
+ ! Initialize FPSCR
+ /* GCC (as of 2.95.1) assumes FPU with double precision mode. */
+ mov.l 7f,r0
+ lds r0,fpscr
#endif
-8:
+ ! Initialize Status Register
+ mov.l 1f,r0 ! MD=1, RB=0, BL=1
+ ldc r0,sr
!
mov.l 2f,r0
mov r0,r15 ! Set initial r15 (stack pointer)
ldc r0,r4_bank ! and stack base
+ !
+ ! Enable cache
+ mov.l 6f,r0
+ jsr @r0
+ nop
! Clear BSS area
mov.l 3f,r1
+ add #4,r1
mov.l 4f,r2
mov #0,r0
-9: mov.l r0,@r1
- cmp/hs r2,r1
- bf/s 9b
- add #4,r1
+9: cmp/hs r2,r1
+ bf/s 9b ! while (r1 < r2)
+ mov.l r0,@-r2
! Start kernel
mov.l 5f,r0
jmp @r0
nop
.balign 4
-1: .long 0xdfffffff ! RB=0, BL=1
-2: .long SYMBOL_NAME(stack)
-3: .long SYMBOL_NAME(__bss_start)
-4: .long SYMBOL_NAME(_end)
-5: .long SYMBOL_NAME(start_kernel)
-
-.data
+1: .long 0x50000000 ! MD=1, RB=0, BL=1
+2: .long SYMBOL_NAME(stack)
+3: .long SYMBOL_NAME(__bss_start)
+4: .long SYMBOL_NAME(_end)
+5: .long SYMBOL_NAME(start_kernel)
+6: .long SYMBOL_NAME(cache_init)
+#if defined(__SH4__)
+7: .long 0x00080000
+#endif
-/*
+/* $Id: irq.c,v 1.4 1999/10/11 13:12:14 gniibe Exp $
+ *
* linux/arch/sh/kernel/irq.c
*
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
*
- * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ * SuperH version: Copyright (C) 1999 Niibe Yutaka
*/
/*
/*
* Controller mappings for all interrupt sources:
*/
-irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
/*
* Special irq handlers.
void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
+ */
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none disable_none
+#define end_none enable_none
+
+struct hw_interrupt_type no_irq_type = {
+ "none",
+ startup_none,
+ shutdown_none,
+ enable_none,
+ disable_none,
+ ack_none,
+ end_none
+};
+
/*
* Generic, controller-independent functions:
*/
struct irqaction * action;
unsigned int status;
+ regs.syscall_nr = -1; /* It's not system call */
+
/* Get IRQ number */
asm volatile("stc r2_bank,%0\n\t"
"shlr2 %0\n\t"
for (;;) {
handle_IRQ_event(irq, ®s, action);
spin_lock(&irq_controller_lock);
-
+
if (!(desc->status & IRQ_PENDING))
break;
desc->status &= ~IRQ_PENDING;
}
desc->status &= ~IRQ_INPROGRESS;
if (!(desc->status & IRQ_DISABLED)){
- irq_desc[irq].handler->end(irq);
+ irq_desc[irq].handler->end(irq);
}
spin_unlock(&irq_controller_lock);
/* Found it - now remove it from the list of entries */
*pp = action->next;
- if (irq_desc[irq].action)
- break;
- irq_desc[irq].status |= IRQ_DISABLED;
- irq_desc[irq].handler->shutdown(irq);
- break;
+ if (!irq_desc[irq].action) {
+ irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].handler->shutdown(irq);
+ }
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
+
+ /* Wait to make sure it's not being used on another CPU */
+ while (irq_desc[irq].status & IRQ_INPROGRESS)
+ barrier();
+ kfree(action);
+ return;
}
printk("Trying to free free IRQ%d\n",irq);
- break;
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
+ return;
}
- spin_unlock_irqrestore(&irq_controller_lock,flags);
}
/*
-/*
+/* $Id: irq_onchip.c,v 1.3 1999/10/11 13:12:19 gniibe Exp $
+ *
* linux/arch/sh/kernel/irq_onchip.c
*
* Copyright (C) 1999 Niibe Yutaka
#include <linux/irq.h>
-
-/*
- * SH (non-)specific no controller code
- */
-
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq)
-{
-}
-
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define shutdown_none disable_none
-#define end_none enable_none
-
-struct hw_interrupt_type no_irq_type = {
- "none",
- startup_none,
- shutdown_none,
- enable_none,
- disable_none,
- ack_none,
- end_none
-};
-
struct ipr_data {
int offset;
int priority;
* IPRC 15-12 11-8 7-4 3-0
*
*/
+#if defined(__sh3__)
#define INTC_IPR 0xfffffee2UL /* Word access */
+#define INTC_SIZE 0x2
+#elif defined(__SH4__)
+#define INTC_IPR 0xffd00004UL /* Word access */
+#define INTC_SIZE 0x4
+#endif
void disable_onChip_irq(unsigned int irq)
{
/* Set priority in IPR to 0 */
int offset = ipr_data[irq-TIMER_IRQ].offset;
- unsigned long intc_ipr_address = INTC_IPR + offset/16;
+ unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE);
unsigned short mask = 0xffff ^ (0xf << (offset%16));
- unsigned long __dummy;
-
- asm volatile("mov.w @%1,%0\n\t"
- "and %2,%0\n\t"
- "mov.w %0,@%1"
- : "=&z" (__dummy)
- : "r" (intc_ipr_address), "r" (mask)
- : "memory" );
+ unsigned long val;
+
+ val = ctrl_inw(intc_ipr_address);
+ val &= mask;
+ ctrl_outw(val, intc_ipr_address);
}
static void enable_onChip_irq(unsigned int irq)
/* Set priority in IPR back to original value */
int offset = ipr_data[irq-TIMER_IRQ].offset;
int priority = ipr_data[irq-TIMER_IRQ].priority;
- unsigned long intc_ipr_address = INTC_IPR + offset/16;
+ unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE);
unsigned short value = (priority << (offset%16));
- unsigned long __dummy;
-
- asm volatile("mov.w @%1,%0\n\t"
- "or %2,%0\n\t"
- "mov.w %0,@%1"
- : "=&z" (__dummy)
- : "r" (intc_ipr_address), "r" (value)
- : "memory" );
+ unsigned long val;
+
+ val = ctrl_inw(intc_ipr_address);
+ val |= value;
+ ctrl_outw(val, intc_ipr_address);
}
void make_onChip_irq(unsigned int irq)
static void mask_and_ack_onChip(unsigned int irq)
{
disable_onChip_irq(irq);
- sti();
}
static void end_onChip_irq(unsigned int irq)
{
enable_onChip_irq(irq);
- cli();
}
void __init init_IRQ(void)
-/*
+/* $Id: process.c,v 1.7 1999/09/23 00:05:41 gniibe Exp $
+ *
* linux/arch/sh/kernel/process.c
*
* Copyright (C) 1995 Linus Torvalds
*
- * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ * SuperH version: Copyright (C) 1999 Niibe Yutaka & Kaz Kojima
*/
/*
#include <linux/irq.h>
+#if defined(__SH4__)
+struct task_struct *last_task_used_math = NULL;
+#endif
+
static int hlt_counter=0;
#define HARD_IDLE_TIMEOUT (HZ / 3)
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("PC: [<%08lx>]", regs->pc);
- printk(" SP: %08lx", regs->u_regs[UREG_SP]);
- printk(" SR: %08lx\n", regs->sr);
- printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
- regs->u_regs[0],regs->u_regs[1],
- regs->u_regs[2],regs->u_regs[3]);
- printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
- regs->u_regs[4],regs->u_regs[5],
- regs->u_regs[6],regs->u_regs[7]);
- printk("R8 : %08lx R9 : %08lx R10: %08lx R11: %08lx\n",
- regs->u_regs[8],regs->u_regs[9],
- regs->u_regs[10],regs->u_regs[11]);
- printk("R12: %08lx R13: %08lx R14: %08lx\n",
- regs->u_regs[12],regs->u_regs[13],
- regs->u_regs[14]);
- printk("MACH: %08lx MACL: %08lx GBR: %08lx PR: %08lx",
+ printk("PC : %08lx SP : %08lx SR : %08lx TEA : %08lx\n",
+ regs->pc, regs->sp, regs->sr, ctrl_inl(MMU_TEA));
+ printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
+ regs->regs[0],regs->regs[1],
+ regs->regs[2],regs->regs[3]);
+ printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
+ regs->regs[4],regs->regs[5],
+ regs->regs[6],regs->regs[7]);
+ printk("R8 : %08lx R9 : %08lx R10 : %08lx R11 : %08lx\n",
+ regs->regs[8],regs->regs[9],
+ regs->regs[10],regs->regs[11]);
+ printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
+ regs->regs[12],regs->regs[13],
+ regs->regs[14]);
+ printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
regs->mach, regs->macl, regs->gbr, regs->pr);
}
*/
void exit_thread(void)
{
+#if defined(__sh3__)
/* nothing to do ... */
+#elif defined(__SH4__)
+#if 0 /* for the time being... */
+ /* Forget lazy fpu state */
+ if (last_task_used_math == current) {
+ set_status_register (SR_FD, 0);
+ write_system_register (fpscr, FPSCR_PR);
+ last_task_used_math = NULL;
+ }
+#endif
+#endif
}
void flush_thread(void)
{
+#if defined(__sh3__)
/* do nothing */
/* Possibly, set clear debug registers */
+#elif defined(__SH4__)
+#if 0 /* for the time being... */
+ /* Forget lazy fpu state */
+ if (last_task_used_math == current) {
+ set_status_register (SR_FD, 0);
+ write_system_register (fpscr, FPSCR_PR);
+ last_task_used_math = NULL;
+ }
+#endif
+#endif
}
void release_thread(struct task_struct *dead_task)
/* Fill in the fpu structure for a core dump.. */
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
{
+#if defined(__SH4__)
+#if 0 /* for the time being... */
+ /* We store the FPU info in the task->thread area. */
+ if (! (regs->sr & SR_FD)) {
+ memcpy (r, ¤t->thread.fpu, sizeof (*r));
+ return 1;
+ }
+#endif
+#endif
return 0; /* Task didn't use the fpu at all. */
}
struct pt_regs *childregs;
childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
-
*childregs = *regs;
+
+#if defined(__SH4__)
+#if 0 /* for the time being... */
+ if (last_task_used_math == current) {
+ set_status_register (SR_FD, 0);
+ sh4_save_fp (p);
+ }
+ /* New tasks loose permission to use the fpu. This accelerates context
+ switching for most programs since they don't use the fpu. */
+ p->thread.sr = (read_control_register (sr) &~ SR_MD) | SR_FD;
+ childregs->sr |= SR_FD;
+#endif
+#endif
if (user_mode(regs)) {
- childregs->u_regs[UREG_SP] = usp;
+ childregs->sp = usp;
} else {
- childregs->u_regs[UREG_SP] = (unsigned long)p+2*PAGE_SIZE;
+ childregs->sp = (unsigned long)p+2*PAGE_SIZE;
}
- childregs->u_regs[0] = 0; /* Set return value for child */
+ childregs->regs[0] = 0; /* Set return value for child */
p->thread.sp = (unsigned long) childregs;
p->thread.pc = (unsigned long) ret_from_fork;
{
/* changed the size calculations - should hopefully work better. lbt */
dump->magic = CMAGIC;
- dump->start_code = 0;
- dump->start_stack = regs->u_regs[UREG_SP] & ~(PAGE_SIZE - 1);
- dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
- dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
- dump->u_dsize -= dump->u_tsize;
- dump->u_ssize = 0;
+ dump->start_code = current->mm->start_code;
+ dump->start_data = current->mm->start_data;
+ dump->start_stack = regs->sp & ~(PAGE_SIZE - 1);
+ dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
+ dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT;
+ dump->u_ssize = (current->mm->start_stack - dump->start_stack +
+ PAGE_SIZE - 1) >> PAGE_SHIFT;
/* Debug registers will come here. */
- if (dump->start_stack < TASK_SIZE)
- dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
-
dump->regs = *regs;
+
+#if 0 /* defined(__SH4__) */
+ /* FPU */
+ memcpy (&dump->regs[EF_SIZE/4], ¤t->thread.fpu,
+ sizeof (current->thread.fpu));
+#endif
}
/*
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- return do_fork(SIGCHLD, regs.u_regs[UREG_SP], ®s);
+ return do_fork(SIGCHLD, regs.sp, ®s);
}
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
struct pt_regs regs)
{
if (!newsp)
- newsp = regs.u_regs[UREG_SP];
+ newsp = regs.sp;
return do_fork(clone_flags, newsp, ®s);
}
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
- regs.u_regs[UREG_SP], ®s);
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, ®s);
}
/*
-/*
+/* $Id: setup.c,v 1.4 1999/10/17 02:49:24 gniibe Exp $
+ *
* linux/arch/sh/kernel/setup.c
*
* Copyright (C) 1999 Niibe Yutaka
#endif
#include <asm/processor.h>
#include <linux/console.h>
+#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
* Machine setup..
*/
-struct sh_cpuinfo boot_cpu_data = { 0, 0, 0, 0, };
-extern int _text, _etext, _edata, _end, _stext, __bss_start;
+struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 0, 0, };
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
#endif
extern int root_mountflags;
+extern int _text, _etext, _edata, _end;
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM ((unsigned char *)empty_zero_page)
+
+#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000))
+#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004))
+#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008))
+#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c))
+#define INITRD_START (*(unsigned long *) (PARAM+0x010))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
+#define MEMORY_END (*(unsigned long *) (PARAM+0x018))
+/* ... */
+#define COMMAND_LINE ((char *) (PARAM+0x100))
+#define COMMAND_LINE_SIZE 256
+
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
-#define COMMAND_LINE_SIZE 1024
static char command_line[COMMAND_LINE_SIZE] = { 0, };
char saved_command_line[COMMAND_LINE_SIZE];
-extern unsigned char *root_fs_image;
-
struct resource standard_io_resources[] = {
{ "dma1", 0x00, 0x1f },
{ "pic1", 0x20, 0x3f },
#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
-
/* System RAM - interrupted by the 640kB-1M hole */
#define code_resource (ram_resources[3])
#define data_resource (ram_resources[4])
{ "Video ROM", 0xc0000, 0xc7fff }
};
-
void __init setup_arch(char **cmdline_p,
unsigned long * memory_start_p,
unsigned long * memory_end_p)
{
- *cmdline_p = command_line;
- *memory_start_p = (unsigned long) &_end;
- *memory_end_p = 0x8c400000; /* For my board. */
- ram_resources[1].end = *memory_end_p-1;
+ unsigned long memory_start, memory_end;
+
+ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+ if (!MOUNT_ROOT_RDONLY)
+ root_mountflags &= ~MS_RDONLY;
+
+ memory_start = (unsigned long) &_end;
+ memory_end = MEMORY_END;
- init_mm.start_code = (unsigned long)&_stext;
+ init_mm.start_code = (unsigned long)&_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
data_resource.start = virt_to_bus(&_etext);
data_resource.end = virt_to_bus(&_edata)-1;
- ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
+ /* Save unparsed command line copy for /proc/cmdline */
+ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+ saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
- initrd_below_start_ok = 1;
- initrd_start = (long)&root_fs_image;
- initrd_end = (long)&__bss_start;
- mount_initrd = 1;
+ memcpy(command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+ command_line[COMMAND_LINE_SIZE-1] = '\0';
+ /* Not support "mem=XXX[kKmM]" command line option. */
+ *cmdline_p = command_line;
-#if 0
- /* Request the standard RAM and ROM resources - they eat up PCI memory space */
- request_resource(&iomem_resource, ram_resources+0);
- request_resource(&iomem_resource, ram_resources+1);
- request_resource(&iomem_resource, ram_resources+2);
- request_resource(ram_resources+1, &code_resource);
- request_resource(ram_resources+1, &data_resource);
-#endif
-
-#if 0
- for (i = 0; i < STANDARD_IO_RESOURCES; i++)
- request_resource(&ioport_resource, standard_io_resources+i);
-#endif
-
-#if 0
- rd_image_start = (long)root_fs_image;
- rd_prompt = 0;
- rd_doload = 1;
-#endif
+ memory_end &= PAGE_MASK;
+ ram_resources[1].end = memory_end-1;
-#if 0
- ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
-
-#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-
- if (!MOUNT_ROOT_RDONLY)
- root_mountflags &= ~MS_RDONLY;
-#endif
+ *memory_start_p = memory_start;
+ *memory_end_p = memory_end;
#ifdef CONFIG_BLK_DEV_INITRD
-#if 0
if (LOADER_TYPE) {
- initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
+ initrd_start = INITRD_START ? INITRD_START : 0;
initrd_end = initrd_start+INITRD_SIZE;
if (initrd_end > memory_end) {
printk("initrd extends beyond end of memory "
}
#endif
+#if 0
+ /*
+ * Request the standard RAM and ROM resources -
+ * they eat up PCI memory space
+ */
+ request_resource(&iomem_resource, ram_resources+0);
+ request_resource(&iomem_resource, ram_resources+1);
+ request_resource(&iomem_resource, ram_resources+2);
+ request_resource(ram_resources+1, &code_resource);
+ request_resource(ram_resources+1, &data_resource);
+ probe_roms();
+
+ /* request I/O space for devices used on all i[345]86 PCs */
+ for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+ request_resource(&ioport_resource, standard_io_resources+i);
+#endif
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+ conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+#endif
#endif
}
{
char *p = buffer;
-#ifdef CONFIG_CPU_SH3
- p += sprintf(p,"cpu family\t: SH3\n"
+#if defined(__sh3__)
+ p += sprintf(p,"cpu family\t: SH-3\n"
"cache size\t: 8K-byte\n");
-#elif CONFIG_CPU_SH4
- p += sprintf(p,"cpu family\t: SH4\n"
- "cache size\t: ??K-byte\n");
+#elif defined(__SH4__)
+ p += sprintf(p,"cpu family\t: SH-4\n"
+ "cache size\t: 8K-byte/16K-byte\n");
#endif
p += sprintf(p, "bogomips\t: %lu.%02lu\n\n",
(loops_per_sec+2500)/500000,
-/*
+/* $Id: signal.c,v 1.10 1999/09/27 23:25:44 gniibe Exp $
+ *
* linux/arch/sh/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
*/
-#include <linux/config.h>
-
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
+#include <asm/pgtable.h>
#define DEBUG_SIG 0
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
- regs.u_regs[0] = -EINTR;
+ regs.regs[0] = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
- regs.u_regs[0] = -EINTR;
+ regs.regs[0] = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- return do_sigaltstack(uss, uoss, regs.u_regs[UREG_SP]);
+ return do_sigaltstack(uss, uoss, regs.sp);
}
struct sigframe
{
struct sigcontext sc;
- /* FPU should come here: SH-3 has no FPU */
+ /* FPU data should come here: SH-3 has no FPU */
unsigned long extramask[_NSIG_WORDS-1];
char retcode[4];
};
{
unsigned int err = 0;
-#define COPY(x) err |= __get_user(regs->x, &sc->x)
- COPY(u_regs[1]);
- COPY(u_regs[2]); COPY(u_regs[3]);
- COPY(u_regs[4]); COPY(u_regs[5]);
- COPY(u_regs[6]); COPY(u_regs[7]);
- COPY(u_regs[8]); COPY(u_regs[9]);
- COPY(u_regs[10]); COPY(u_regs[11]);
- COPY(u_regs[12]); COPY(u_regs[13]);
- COPY(u_regs[14]); COPY(u_regs[15]);
- COPY(gbr); COPY(mach);
- COPY(macl); COPY(pr);
- COPY(sr); COPY(pc);
+#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
+ COPY(regs[1]);
+ COPY(regs[2]); COPY(regs[3]);
+ COPY(regs[4]); COPY(regs[5]);
+ COPY(regs[6]); COPY(regs[7]);
+ COPY(regs[8]); COPY(regs[9]);
+ COPY(regs[10]); COPY(regs[11]);
+ COPY(regs[12]); COPY(regs[13]);
+ COPY(regs[14]); COPY(sp);
+ COPY(gbr); COPY(mach);
+ COPY(macl); COPY(pr);
+ COPY(sr); COPY(pc);
#undef COPY
regs->syscall_nr = -1; /* disable syscall checks */
- err |= __get_user(*r0_p, &sc->u_regs[0]);
+ err |= __get_user(*r0_p, &sc->sc_regs[0]);
return err;
}
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- struct sigframe *frame = (struct sigframe *)regs.u_regs[UREG_SP];
+ struct sigframe *frame = (struct sigframe *)regs.sp;
sigset_t set;
int r0;
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- struct rt_sigframe *frame = (struct rt_sigframe *)regs.u_regs[UREG_SP];
+ struct rt_sigframe *frame = (struct rt_sigframe *)regs.sp;
sigset_t set;
stack_t st;
int r0;
goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs.u_regs[UREG_SP]);
+ do_sigaltstack(&st, NULL, regs.sp);
return r0;
{
int err = 0;
-#define COPY(x) err |= __put_user(regs->x, &sc->x)
- COPY(u_regs[0]); COPY(u_regs[1]);
- COPY(u_regs[2]); COPY(u_regs[3]);
- COPY(u_regs[4]); COPY(u_regs[5]);
- COPY(u_regs[6]); COPY(u_regs[7]);
- COPY(u_regs[8]); COPY(u_regs[9]);
- COPY(u_regs[10]); COPY(u_regs[11]);
- COPY(u_regs[12]); COPY(u_regs[13]);
- COPY(u_regs[14]); COPY(u_regs[15]);
- COPY(gbr); COPY(mach);
- COPY(macl); COPY(pr);
- COPY(sr); COPY(pc);
+#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
+ COPY(regs[0]); COPY(regs[1]);
+ COPY(regs[2]); COPY(regs[3]);
+ COPY(regs[4]); COPY(regs[5]);
+ COPY(regs[6]); COPY(regs[7]);
+ COPY(regs[8]); COPY(regs[9]);
+ COPY(regs[10]); COPY(regs[11]);
+ COPY(regs[12]); COPY(regs[13]);
+ COPY(regs[14]); COPY(sp);
+ COPY(gbr); COPY(mach);
+ COPY(macl); COPY(pr);
+ COPY(sr); COPY(pc);
#undef COPY
/* non-iBCS2 extensions.. */
int err = 0;
int signal;
- frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame));
+ frame = get_sigframe(ka, regs->sp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
regs->pr = (unsigned long) ka->sa.sa_restorer;
} else {
/* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */
-#ifdef CONFIG_LITTLE_ENDIAN
- unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8);
+#ifdef __LITTLE_ENDIAN__
+ unsigned long code = 0xc300e000 | (__NR_sigreturn);
#else
unsigned long code = 0xe000c300 | (__NR_sigreturn << 16);
#endif
goto give_sigsegv;
/* Set up registers for signal handler */
- regs->u_regs[UREG_SP] = (unsigned long) frame;
- regs->u_regs[4] = signal; /* Arg for signal handler */
+ regs->sp = (unsigned long) frame;
+ regs->regs[4] = signal; /* Arg for signal handler */
regs->pc = (unsigned long) ka->sa.sa_handler;
set_fs(USER_DS);
current->comm, current->pid, frame, regs->pc, regs->pr);
#endif
+ flush_icache_range(regs->pr, regs->pr+4);
return;
give_sigsegv:
int err = 0;
int signal;
- frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame));
+ frame = get_sigframe(ka, regs->sp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->u_regs[UREG_SP]),
- &frame->uc.uc_stack.ss_flags);
+ err |= __put_user((void *)current->sas_ss_sp,
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
regs->pr = (unsigned long) ka->sa.sa_restorer;
} else {
/* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */
-#ifdef CONFIG_LITTLE_ENDIAN
- unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8);
+#ifdef __LITTLE_ENDIAN__
+ unsigned long code = 0xc300e000 | (__NR_sigreturn);
#else
unsigned long code = 0xe000c300 | (__NR_sigreturn << 16);
#endif
goto give_sigsegv;
/* Set up registers for signal handler */
- regs->u_regs[UREG_SP] = (unsigned long) frame;
- regs->u_regs[4] = signal; /* Arg for signal handler */
+ regs->sp = (unsigned long) frame;
+ regs->regs[4] = signal; /* Arg for signal handler */
regs->pc = (unsigned long) ka->sa.sa_handler;
set_fs(USER_DS);
current->comm, current->pid, frame, regs->pc, regs->pr);
#endif
+ flush_icache_range(regs->pr, regs->pr+4);
return;
give_sigsegv:
/* Are we from a system call? */
if (regs->syscall_nr >= 0) {
/* If so, check system call restarting.. */
- switch (regs->u_regs[0]) {
+ switch (regs->regs[0]) {
case -ERESTARTNOHAND:
- regs->u_regs[0] = -EINTR;
+ regs->regs[0] = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->u_regs[0] = -EINTR;
+ regs->regs[0] = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
- regs->u_regs[0] = regs->syscall_nr;
+ regs->regs[0] = regs->syscall_nr;
regs->pc -= 2;
}
}
/* NOTREACHED */
}
}
-
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs);
return 1;
/* Did we come from a system call? */
if (regs->syscall_nr >= 0) {
/* Restart the system call - no handlers present */
- if (regs->u_regs[0] == -ERESTARTNOHAND ||
- regs->u_regs[0] == -ERESTARTSYS ||
- regs->u_regs[0] == -ERESTARTNOINTR) {
- regs->u_regs[0] = regs->syscall_nr;
+ if (regs->regs[0] == -ERESTARTNOHAND ||
+ regs->regs[0] == -ERESTARTSYS ||
+ regs->regs[0] == -ERESTARTNOINTR) {
+ regs->regs[0] = regs->syscall_nr;
regs->pc -= 2;
}
}
/*
- * linux/arch/i386/kernel/sys_i386.c
+ * linux/arch/sh/kernel/sys_sh.c
*
* This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/i386
+ * have a non-standard calling sequence on the Linux/SuperH
* platform.
+ *
+ * Taken from i386 version.
*/
#include <linux/errno.h>
return error;
}
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
- */
-
-struct mmap_arg_struct {
- unsigned long addr;
- unsigned long len;
- unsigned long prot;
- unsigned long flags;
- unsigned long fd;
- unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+asmlinkage unsigned long
+sys_mmap(int fd, unsigned long addr,
+ unsigned long len, unsigned long prot,
+ unsigned long flags, unsigned long off)
{
int error = -EFAULT;
- struct file * file = NULL;
- struct mmap_arg_struct a;
-
- if (copy_from_user(&a, arg, sizeof(a)))
- return -EFAULT;
+ struct file *file = NULL;
down(¤t->mm->mmap_sem);
lock_kernel();
- if (!(a.flags & MAP_ANONYMOUS)) {
+ if (!(flags & MAP_ANONYMOUS)) {
error = -EBADF;
- file = fget(a.fd);
+ file = fget(fd);
if (!file)
goto out;
}
- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+ error = do_mmap(file, addr, len, prot, flags, off);
if (file)
fput(file);
out:
unlock_kernel();
up(¤t->mm->mmap_sem);
- return error;
-}
-
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
-struct sel_arg_struct {
- unsigned long n;
- fd_set *inp, *outp, *exp;
- struct timeval *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct *arg)
-{
- struct sel_arg_struct a;
- if (copy_from_user(&a, arg, sizeof(a)))
- return -EFAULT;
- /* sys_select() does the appropriate kernel locking */
- return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+ return error;
}
/*
return -EINVAL;
}
-/*
- * Old cruft
- */
asmlinkage int sys_uname(struct old_utsname * name)
{
int err;
return err?-EFAULT:0;
}
-asmlinkage int sys_olduname(struct oldold_utsname * name)
-{
- int error;
-
- if (!name)
- return -EFAULT;
- if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
- return -EFAULT;
-
- down(&uts_sem);
-
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
- error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
- error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
- error |= __put_user(0,name->release+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
- error |= __put_user(0,name->version+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
- error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-
- up(&uts_sem);
-
- error = error ? -EFAULT : 0;
-
- return error;
-}
-
asmlinkage int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
+++ /dev/null
-unsigned char root_fs_image[]
-__attribute__((__section__(".data.disk_image")))
-= {
-0x1f,0x8b,0x08,0x08,0x5d,0xd5,0xc7,0x37,0x00,0x03,0x72,0x2e,0x62,0x69,0x6e,0x00,
-0xed,0xdc,0x3f,0x6c,0x1b,0x55,0x1c,0xc0,0xf1,0xdf,0xf9,0xdc,0x04,0x27,0x69,0xb1,
-0x93,0x14,0x10,0x48,0x91,0xd3,0x02,0x4d,0x8a,0xb8,0xd4,0x21,0x8a,0x09,0x02,0x02,
-0xb5,0x4a,0xab,0x52,0x65,0x69,0x11,0x03,0x42,0xc2,0xb1,0x8f,0xc4,0x92,0xe3,0x03,
-0x9f,0x8d,0xca,0x14,0xd8,0x88,0x2a,0xa6,0x0e,0x88,0xa9,0x20,0xb1,0x87,0x8d,0xa5,
-0x5b,0x86,0xcc,0x90,0x78,0x77,0xd4,0x60,0x75,0xa9,0x40,0xe2,0xdf,0xd0,0x42,0x78,
-0x77,0xef,0x9c,0x38,0x24,0x72,0x49,0x20,0xc9,0x70,0xdf,0x8f,0xf2,0xf3,0xd9,0x77,
-0xbf,0xf3,0xbb,0x67,0xbf,0xdf,0xf9,0x4f,0xf4,0x2c,0x02,0x20,0xac,0xe2,0x2a,0x5e,
-0x53,0x61,0xaa,0x18,0x0e,0xd6,0x19,0xad,0x09,0x49,0x1d,0x5e,0x5e,0x7d,0x75,0x39,
-0xfd,0x6c,0x6d,0x39,0x6d,0x48,0xbf,0x5c,0xfd,0xc9,0xf0,0xf3,0x56,0xd5,0x3a,0x99,
-0xba,0xf7,0xd0,0x76,0x8a,0x53,0x5f,0xc4,0xdf,0xcd,0x24,0x56,0x6e,0x9e,0x59,0xb9,
-0x30,0x3e,0x73,0x3b,0xf7,0x3f,0x76,0x01,0xc0,0x3e,0x79,0x75,0x1f,0x55,0x71,0x4c,
-0x74,0xfd,0x47,0x8f,0xf6,0x70,0x00,0x1c,0xa2,0x8d,0x8d,0x49,0x6f,0xf1,0xc9,0x06,
-0x00,0x00,0x08,0x8d,0xe6,0xfb,0x00,0xef,0x73,0x7c,0x33,0x0e,0xf3,0xfd,0xc7,0xbd,
-0xd7,0xc5,0xff,0xd0,0x31,0x5a,0x5b,0x4e,0xf7,0x05,0xa1,0xb7,0x1c,0x93,0x48,0x4b,
-0x5e,0xe7,0x61,0x1e,0x14,0x80,0x50,0xf0,0xcf,0x3f,0xe7,0x76,0x3b,0xff,0x45,0xe4,
-0x89,0x96,0xbc,0x47,0x54,0xc4,0x54,0x74,0xa9,0xe8,0x56,0xd1,0xa3,0xe2,0xb8,0x8a,
-0x13,0x2a,0x1e,0x15,0xfd,0xfd,0x68,0x42,0x45,0xaf,0x8a,0xbe,0xbd,0xb6,0xaf,0xce,
-0x7f,0x7f,0xaa,0x76,0xef,0x07,0xd1,0x6c,0xbf,0xf5,0xfc,0xd7,0xbf,0xf7,0xae,0x6d,
-0x32,0xda,0x6c,0x6b,0xb6,0x7f,0x56,0x9d,0x77,0x4f,0x05,0xb1,0x5b,0xfb,0x27,0x0f,
-0xa8,0xfd,0x6f,0x06,0xf5,0xf2,0xfe,0x8e,0xfe,0xff,0x63,0xaf,0xff,0xf0,0xc5,0x54,
-0xdb,0xfe,0x7f,0x7a,0xeb,0xf2,0x15,0x53,0xe4,0xe6,0xaa,0x7e,0xed,0x19,0x0b,0xda,
-0xbf,0x75,0xd9,0xd8,0xd6,0xff,0xc7,0xf6,0xdf,0x7c,0xdb,0xf6,0x37,0xbe,0xd6,0x63,
-0x6a,0xe7,0xe3,0xbf,0x7d,0x2f,0xcb,0x1a,0x29,0x16,0x4a,0xd5,0xeb,0xe5,0x7d,0x7c,
-0x73,0xde,0xae,0x7d,0xaf,0x8f,0x3d,0x2a,0xc3,0xda,0xbc,0x1e,0x51,0x6d,0xe9,0x31,
-0xde,0xaf,0x8e,0xac,0xe8,0xb8,0x95,0xe7,0xde,0x77,0xaa,0xa5,0xbc,0x1e,0xf3,0x3d,
-0x62,0x4a,0xde,0xfe,0xc8,0x1f,0xfb,0x3d,0xea,0x49,0x71,0xa7,0x0b,0x25,0x6f,0xfc,
-0xdf,0x36,0x3b,0x65,0xdf,0x07,0x08,0xe0,0x48,0xe8,0xd7,0xb2,0xad,0xfa,0xff,0xd5,
-0xd4,0xf5,0x0f,0x20,0x24,0xf8,0xa7,0x1f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,
-0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,
-0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,
-0x10,0x4a,0x7a,0x4e,0xcf,0xce,0xf9,0x3f,0xde,0xbc,0xb6,0xbb,0x66,0xa7,0xe4,0x9c,
-0x92,0xeb,0x14,0xed,0xa3,0x3d,0x48,0x00,0x07,0x42,0xcf,0xe3,0xdb,0x59,0xff,0xde,
-0x7c,0xd6,0xbb,0x66,0x54,0x0a,0xa5,0x42,0xe5,0x68,0x8f,0x10,0xc0,0x41,0x99,0xbf,
-0x70,0xe5,0x0d,0x23,0xd2,0x32,0x43,0x38,0x22,0x67,0xc5,0x9f,0x32,0x1c,0xff,0x4a,
-0x2d,0xc7,0xd4,0xd5,0x75,0x7f,0xfd,0x98,0x24,0xd5,0xb6,0x21,0x89,0xf9,0x53,0xe1,
-0x83,0x1d,0xe2,0x41,0x18,0xd3,0x3a,0xfc,0x9f,0x11,0x34,0x74,0x78,0xb7,0x07,0x83,
-0xd8,0xd4,0xe1,0x27,0x67,0xd6,0x8d,0x46,0x7c,0xa4,0x51,0x8f,0xd6,0x3a,0x4a,0xbf,
-0x2c,0xc9,0x7b,0xa7,0x3f,0x33,0x16,0xcc,0x5a,0xb4,0x61,0xd6,0xa3,0x4b,0xe2,0xdc,
-0x91,0xee,0xd2,0xef,0x22,0x89,0xa7,0x55,0xbc,0x38,0xd2,0x98,0xff,0xb9,0x1e,0xf1,
-0xb2,0xa6,0xcd,0xf3,0x89,0x85,0xce,0x75,0xa3,0xf6,0x78,0xe3,0xa4,0x97,0x27,0xb1,
-0xc5,0xbf,0x24,0x76,0x6a,0x68,0xa1,0x7b,0xa5,0x6f,0x4d,0x3e,0x34,0x52,0xe9,0x1b,
-0x0f,0xf2,0xa7,0x7f,0x34,0xea,0xcf,0x2c,0xc9,0xe2,0x1f,0x6b,0x6a,0xfb,0xf7,0x27,
-0xd6,0x0d,0xab,0xd7,0xbe,0xb3,0x26,0x03,0x89,0x86,0x0c,0xf4,0xd6,0x33,0x03,0x7d,
-0x4b,0xf2,0x43,0xd7,0xba,0x21,0xb1,0x5a,0xac,0x71,0xdc,0xbb,0x17,0x2f,0x4f,0xed,
-0x7b,0xe6,0xc6,0x83,0xc5,0xdf,0xbc,0xf5,0xaa,0xcd,0x97,0xe5,0x9d,0xcf,0xe7,0x55,
-0xbf,0x2a,0xf2,0xdd,0x93,0x1b,0xea,0xf6,0xb5,0x6b,0xb3,0x05,0x37,0xa9,0xfe,0xae,
-0x56,0x3f,0xb0,0xcb,0x97,0x06,0xbd,0xe9,0xda,0x32,0x39,0xd9,0x25,0xae,0x33,0x67,
-0x57,0x66,0x0b,0xa5,0x99,0x64,0xb5,0x54,0x75,0xab,0xd9,0xa2,0x65,0x59,0xde,0xc6,
-0x4b,0x76,0xb1,0xe8,0x24,0xdf,0x76,0xca,0xc5,0xbc,0x97,0x7c,0x31,0x93,0x79,0x29,
-0x39,0x74,0x71,0xea,0xad,0xe1,0xa4,0x3d,0x93,0x73,0x9f,0x1f,0xb5,0x26,0x52,0xd6,
-0xf8,0x78,0x32,0x35,0x31,0x31,0x71,0xee,0x85,0xd4,0x58,0x72,0xc8,0x5f,0x9d,0xb2,
-0x52,0xd6,0x68,0xb2,0x6c,0x17,0xed,0xac,0x6b,0x0f,0x8b,0x58,0xee,0xc7,0x73,0x95,
-0xec,0xb4,0x5a,0x56,0xca,0x7a,0x39,0xdb,0xbc,0x56,0xb1,0xaf,0x57,0xc4,0x2a,0x3b,
-0xf9,0x6c,0x25,0x2b,0x96,0xbe,0xcc,0x55,0x9c,0xb2,0xab,0x6e,0xe8,0xc5,0xb4,0xab,
-0x2e,0x72,0xce,0xdc,0x9c,0x5d,0xda,0xd3,0xe9,0xfb,0xa9,0xe0,0xf9,0xeb,0xf0,0xfb,
-0x2f,0xe2,0xc5,0xb7,0x2d,0xdb,0x9b,0x9f,0x14,0x07,0x83,0xbc,0x88,0x7e,0x9e,0x0c,
-0x15,0xf2,0xea,0x2e,0x79,0xc3,0x41,0x9e,0xa9,0xc7,0x81,0xd1,0x3a,0x16,0x64,0x6b,
-0x1c,0xc9,0xc8,0xd6,0xb8,0x69,0x9b,0x37,0xfe,0x2f,0xf3,0x5e,0x11,0xfd,0x93,0x0d,
-0x0f,0x6b,0xf7,0xbc,0x6c,0x9b,0x1e,0xef,0xe7,0xa5,0x77,0xc9,0x4b,0xe8,0xfb,0xda,
-0x5c,0xfd,0xa5,0xba,0x78,0x73,0x97,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x87,0xe8,0x6f,0x20,0x01,0xec,0xc5,0x00,0x00,0x01,0x00,
-};
-/*
+/* $Id: time.c,v 1.2 1999/10/11 13:12:02 gniibe Exp $
+ *
* linux/arch/sh/kernel/time.c
*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
*
* Some code taken from i386 version.
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*/
+#include <linux/config.h>
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/timex.h>
#include <linux/irq.h>
+#define TMU_TOCR_INIT 0x00
+#define TMU0_TCR_INIT 0x0020
+#define TMU_TSTR_INIT 1
+
+#if defined(__sh3__)
#define TMU_TOCR 0xfffffe90 /* Byte access */
#define TMU_TSTR 0xfffffe92 /* Byte access */
#define TMU0_TCNT 0xfffffe98 /* Long access */
#define TMU0_TCR 0xfffffe9c /* Word access */
-#define TMU_TOCR_INIT 0x00
-#define TMU0_TCR_INIT 0x0020
-#define TMU_TSTR_INIT 1
-
-#define CLOCK_MHZ (60/4)
#define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? */
+/* SH-3 RTC */
+#define R64CNT 0xfffffec0
+#define RSECCNT 0xfffffec2
+#define RMINCNT 0xfffffec4
+#define RHRCNT 0xfffffec6
+#define RWKCNT 0xfffffec8
+#define RDAYCNT 0xfffffeca
+#define RMONCNT 0xfffffecc
+#define RYRCNT 0xfffffece
+#define RSECAR 0xfffffed0
+#define RMINAR 0xfffffed2
+#define RHRAR 0xfffffed4
+#define RWKAR 0xfffffed6
+#define RDAYAR 0xfffffed8
+#define RMONAR 0xfffffeda
+#define RCR1 0xfffffedc
+#define RCR2 0xfffffede
+
+#elif defined(__SH4__)
+#define TMU_TOCR 0xffd80000 /* Byte access */
+#define TMU_TSTR 0xffd80004 /* Byte access */
+
+#define TMU0_TCOR 0xffd80008 /* Long access */
+#define TMU0_TCNT 0xffd8000c /* Long access */
+#define TMU0_TCR 0xffd80010 /* Word access */
+
+#define INTERVAL 83333
+
+/* SH-4 RTC */
+#define R64CNT 0xffc80000
+#define RSECCNT 0xffc80004
+#define RMINCNT 0xffc80008
+#define RHRCNT 0xffc8000c
+#define RWKCNT 0xffc80010
+#define RDAYCNT 0xffc80014
+#define RMONCNT 0xffc80018
+#define RYRCNT 0xffc8001c /* 16bit */
+#define RSECAR 0xffc80020
+#define RMINAR 0xffc80024
+#define RHRAR 0xffc80028
+#define RWKAR 0xffc8002c
+#define RDAYAR 0xffc80030
+#define RMONAR 0xffc80034
+#define RCR1 0xffc80038
+#define RCR2 0xffc8003c
+#endif
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
extern rwlock_t xtime_lock;
#define TICK_SIZE tick
write_unlock_irq(&xtime_lock);
}
-/*
- */
static int set_rtc_time(unsigned long nowtime)
{
-/* XXX should be implemented XXXXXXXXXX */
- int retval = -1;
+#ifdef CONFIG_SH_CPU_RTC
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+
+ ctrl_outb(2, RCR2); /* reset pre-scaler & stop RTC */
+
+ cmos_minutes = ctrl_inb(RMINCNT);
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ ctrl_outb(real_seconds, RSECCNT);
+ ctrl_outb(real_minutes, RMINCNT);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_time: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ ctrl_outb(2, RCR2); /* start RTC */
return retval;
+#else
+ /* XXX should support other clock devices? */
+ return -1;
+#endif
}
/* last time the RTC clock got updated */
*/
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned long __dummy;
+ unsigned long timer_status;
/* Clear UNF bit */
- asm volatile("mov.w %1,%0\n\t"
- "and %2,%0\n\t"
- "mov.w %0,%1"
- : "=&z" (__dummy)
- : "m" (__m(TMU0_TCR)), "r" (~0x100));
+ timer_status = ctrl_inw(TMU0_TCR);
+ timer_status &= ~0x100;
+ ctrl_outw(timer_status, TMU0_TCR);
/*
* Here we are in the timer irq handler. We just have irqs locally
static unsigned long get_rtc_time(void)
{
-/* XXX not implemented yet */
+#ifdef CONFIG_SH_CPU_RTC
+ unsigned int sec, min, hr, wk, day, mon, yr, yr100;
+
+ again:
+ ctrl_outb(1, RCR1); /* clear CF bit */
+ do {
+ sec = ctrl_inb(RSECCNT);
+ min = ctrl_inb(RMINCNT);
+ hr = ctrl_inb(RHRCNT);
+ wk = ctrl_inb(RWKCNT);
+ day = ctrl_inb(RDAYCNT);
+ mon = ctrl_inb(RMONCNT);
+#if defined(__SH4__)
+ yr = ctrl_inw(RYRCNT);
+ yr100 = (yr >> 8);
+ yr &= 0xff;
+#else
+ yr = ctrl_inb(RYRCNT);
+ yr100 = (yr == 0x99) ? 0x19 : 0x20;
+#endif
+ } while ((ctrl_inb(RCR1) & 0x80) != 0);
+
+ BCD_TO_BIN(yr100);
+ BCD_TO_BIN(yr);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(hr);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(sec);
+
+ if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+ hr > 23 || min > 59 || sec > 59) {
+ printk(KERN_ERR
+ "SH RTC: invalid value, resetting to 1 Jan 2000\n");
+ ctrl_outb(2, RCR2); /* reset, stop */
+ ctrl_outb(0, RSECCNT);
+ ctrl_outb(0, RMINCNT);
+ ctrl_outb(0, RHRCNT);
+ ctrl_outb(6, RWKCNT);
+ ctrl_outb(1, RDAYCNT);
+ ctrl_outb(1, RMONCNT);
+#if defined(__SH4__)
+ ctrl_outw(0x2000, RYRCNT);
+#else
+ ctrl_outb(0, RYRCNT);
+#endif
+ ctrl_outb(1, RCR2); /* start */
+ goto again;
+ }
+
+ return mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+#else
+ /* XXX should support other clock devices? */
return 0;
+#endif
}
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
void __init time_init(void)
{
- unsigned long __dummy;
-
xtime.tv_sec = get_rtc_time();
xtime.tv_usec = 0;
setup_irq(TIMER_IRQ, &irq0);
/* Start TMU0 */
- asm volatile("mov %1,%0\n\t"
- "mov.b %0,%2 ! external clock input\n\t"
- "mov %3,%0\n\t"
- "mov.w %0,%4 ! enable timer0 interrupt\n\t"
- "mov.l %5,%6\n\t"
- "mov.l %5,%7\n\t"
- "mov %8,%0\n\t"
- "mov.b %0,%9"
- : "=&z" (__dummy)
- : "i" (TMU_TOCR_INIT), "m" (__m(TMU_TOCR)),
- "i" (TMU0_TCR_INIT), "m" (__m(TMU0_TCR)),
- "r" (INTERVAL), "m" (__m(TMU0_TCOR)), "m" (__m(TMU0_TCNT)),
- "i" (TMU_TSTR_INIT), "m" (__m(TMU_TSTR)));
+ ctrl_outb(TMU_TOCR_INIT,TMU_TOCR);
+ ctrl_outw(TMU0_TCR_INIT,TMU0_TCR);
+ ctrl_outl(INTERVAL,TMU0_TCOR);
+ ctrl_outl(INTERVAL,TMU0_TCNT);
+ ctrl_outb(TMU_TSTR_INIT,TMU_TSTR);
+
#if 0
/* Start RTC */
asm volatile("");
-/*
+/* $Id: traps.c,v 1.3 1999/09/21 14:37:19 gniibe Exp $
+ *
* linux/arch/sh/traps.c
*
* SuperH version: Copyright (C) 1999 Niibe Yutaka
#define VMALLOC_OFFSET (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
-static void show_registers(struct pt_regs *regs)
-{/* Not implemented yet. */
-}
-
spinlock_t die_lock;
void die(const char * str, struct pt_regs * regs, long err)
console_verbose();
spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
- show_registers(regs);
+ show_regs(regs);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
L_TARGET = lib.a
-# L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \
-# usercopy.o getuser.o putuser.o
-L_OBJS = delay.o memcpy.o memset.o memmove.o csum_partial_copy.o \
- wordcopy.o checksum.o # usercopy.o getuser.o putuser.o
+L_OBJS = delay.o memcpy.o memset.o memmove.o old-checksum.o \
+ checksum.o
include $(TOPDIR)/Rules.make
--- /dev/null
+/* $Id: checksum.S,v 1.1 1999/09/18 16:56:53 gniibe Exp $
+ *
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ * handling.
+ * Andi Kleen, add zeroing on error
+ * converted to pure assembler
+ *
+ * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/errno.h>
+#include <linux/linkage.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+ * unsigned int csum_partial(const unsigned char *buf, int len,
+ * unsigned int sum);
+ */
+
+.text
+ENTRY(csum_partial)
+ /*
+ * Experiments with Ethernet and SLIP connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+ mov r5,r1
+ mov r4,r0
+ tst #2,r0 ! Check alignment.
+ bt 2f ! Jump if alignment is ok.
+ !
+ add #-2,r5 ! Alignment uses up two bytes.
+ cmp/pz r5 !
+ bt/s 1f ! Jump if we had at least two bytes.
+ clrt
+ bra 6f
+ add #2,r5 ! r5 was < 2. Deal with it.
+1:
+ mov.w @r4+,r0
+ extu.w r0,r0
+ addc r0,r6
+ bf 2f
+ add #1,r6
+2:
+ mov #-5,r0
+ shld r0,r5
+ tst r5,r5
+ bt/s 4f ! if it's =0, go to 4f
+ clrt
+3:
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ mov.l @r4+,r0
+ addc r0,r6
+ movt r0
+ dt r5
+ bf/s 3b
+ cmp/eq #1,r0
+ mov #0,r0
+ addc r0,r6
+4:
+ mov r1,r5
+ mov #0x1c,r0
+ and r0,r5
+ tst r5,r5
+ bt/s 6f
+ clrt
+ shlr2 r5
+5:
+ mov.l @r4+,r0
+ addc r0,r6
+ movt r0
+ dt r5
+ bf/s 5b
+ cmp/eq #1,r0
+ mov #0,r0
+ addc r0,r6
+6:
+ mov r1,r5
+ mov #3,r0
+ and r0,r5
+ tst r5,r5
+ bt 9f ! if it's =0 go to 9f
+ mov #2,r1
+ cmp/hs r1,r5
+ bf 7f
+ mov.w @r4+,r0
+ extu.w r0,r0
+ cmp/eq r1,r5
+ bt/s 8f
+ clrt
+ shll16 r0
+ addc r0,r6
+7:
+ mov.b @r4+,r0
+ extu.b r0,r0
+8:
+ addc r0,r6
+ mov #0,r0
+ addc r0,r6
+9:
+ rts
+ mov r6,r0
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
+ int sum, int *src_err_ptr, int *dst_err_ptr)
+ */
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ * DST definitions? It's damn hard to trigger all cases. I hope I got
+ * them all but there's no guarantee.
+ */
+
+#define SRC(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6001f ; \
+ .previous
+
+#define DST(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6002f ; \
+ .previous
+
+ENTRY(csum_partial_copy_generic)
+ mov.l r5,@-r15
+ mov.l r6,@-r15
+
+ mov #2,r0
+ tst r0,r5 ! Check alignment.
+ bt 2f ! Jump if alignment is ok.
+ add #-2,r6 ! Alignment uses up two bytes.
+ cmp/pz r6 ! Jump if we had at least two bytes.
+ bt/s 1f
+ clrt
+ bra 4f
+ add #2,r6 ! ecx was < 2. Deal with it.
+SRC(1: mov.w @r4+,r0 )
+DST( mov.w r0,@r5 )
+ add #2,r5
+ extu.w r0,r0
+ addc r0,r7
+ mov #0,r0
+ addc r0,r7
+2:
+ mov r6,r2
+ mov #-5,r0
+ shld r0,r6
+ tst r6,r6
+ bf/s 2f
+ clrt
+SRC(1: mov.l @r4+,r0 )
+SRC( mov.l @r4+,r1 )
+ addc r0,r7
+DST( mov.l r0,@r5 )
+ add #4,r5
+ addc r1,r7
+DST( mov.l r1,@r5 )
+ add #4,r5
+
+SRC( mov.l @r4+,r0 )
+SRC( mov.l @r4+,r1 )
+ addc r0,r7
+DST( mov.l r0,@r5 )
+ add #4,r5
+ addc r1,r7
+DST( mov.l r1,@r5 )
+ add #4,r5
+
+SRC( mov.l @r4+,r0 )
+SRC( mov.l @r4+,r1 )
+ addc r0,r7
+DST( mov.l r0,@r5 )
+ add #4,r5
+ addc r1,r7
+DST( mov.l r1,@r5 )
+ add #4,r5
+
+SRC( mov.l @r4+,r0 )
+SRC( mov.l @r4+,r1 )
+ addc r0,r7
+DST( mov.l r0,@r5 )
+ add #4,r5
+ addc r1,r7
+DST( mov.l r1,@r5 )
+ add #4,r5
+ movt r0
+ dt r6
+ bf/s 1b
+ cmp/eq #1,r0
+ mov #0,r0
+ addc r0,r7
+
+2: mov r2,r6
+ mov #0x1c,r0
+ and r0,r6
+ cmp/pl r6
+ bf/s 4f
+ clrt
+ shlr2 r6
+SRC(3: mov.l @r4+,r0 )
+ addc r0,r7
+DST( mov.l r0,@r5 )
+ add #4,r5
+ movt r0
+ dt r6
+ bf/s 3b
+ cmp/eq #1,r0
+ mov #0,r0
+ addc r0,r7
+4: mov r2,r6
+ mov #3,r0
+ and r0,r6
+ cmp/pl r6
+ bf 7f
+ mov #2,r1
+ cmp/hs r1,r6
+ bf 5f
+SRC( mov.w @r4+,r0 )
+DST( mov.w r0,@r5 )
+ extu.w r0,r0
+ add #2,r5
+ cmp/eq r1,r6
+ bt/s 6f
+ clrt
+ shll16 r0
+ addc r0,r7
+SRC(5: mov.b @r4+,r0 )
+DST( mov.b r0,@r5 )
+ extu.b r0,r0
+6: addc r0,r7
+ mov #0,r0
+ addc r0,r7
+7:
+5000:
+
+# Exception handler:
+.section .fixup, "ax"
+
+6001:
+ mov.l @(8,r15),r0 ! src_err_ptr
+ mov #-EFAULT,r1
+ mov.l r1,@r0
+
+ ! zero the complete destination - computing the rest
+ ! is too much work
+ mov.l @(4,r15),r5 ! dst
+ mov.l @r15,r6 ! len
+ mov #0,r7
+1: mov.b r7,@r5
+ dt r6
+ bf/s 1b
+ add #1,r5
+ mov.l 8000f,r0
+ jmp @r0
+ nop
+ .balign 4
+8000: .long 5000b
+
+6002:
+ mov.l @(12,r15),r0 ! dst_err_ptr
+ mov #-EFAULT,r1
+ mov.l r1,@r0
+ mov.l 8001f,r0
+ jmp @r0
+ nop
+ .balign 4
+8001: .long 5000b
+
+.previous
+ add #8,r15
+ rts
+ mov r7,r0
+++ /dev/null
-/*
- * Taken from:
- * arch/alpha/lib/checksum.c
- *
- * This file contains network checksum routines that are better done
- * in an architecture-specific manner due to speed..
- */
-
-#include <linux/string.h>
-
-#include <asm/byteorder.h>
-
-static inline unsigned short from64to16(unsigned long long x)
-{
- /* add up 32-bit words for 33 bits */
- x = (x & 0xffffffff) + (x >> 32);
- /* add up 16-bit and 17-bit words for 17+c bits */
- x = (x & 0xffff) + (x >> 16);
- /* add up 16-bit and 2-bit for 16+c bit */
- x = (x & 0xffff) + (x >> 16);
- /* add up carry.. */
- x = (x & 0xffff) + (x >> 16);
- return x;
-}
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented.
- */
-unsigned short int csum_tcpudp_magic(unsigned long saddr,
- unsigned long daddr,
- unsigned short len,
- unsigned short proto,
- unsigned int sum)
-{
- return ~from64to16(saddr + daddr + sum +
- ((unsigned long) ntohs(len) << 16) +
- ((unsigned long) proto << 8));
-}
-
-unsigned int csum_tcpudp_nofold(unsigned long saddr,
- unsigned long daddr,
- unsigned short len,
- unsigned short proto,
- unsigned int sum)
-{
- unsigned long long result;
-
- result = (saddr + daddr + sum +
- ((unsigned long) ntohs(len) << 16) +
- ((unsigned long) proto << 8));
-
- /* Fold down to 32-bits so we don't loose in the typedef-less
- network stack. */
- /* 64 to 33 */
- result = (result & 0xffffffff) + (result >> 32);
- /* 33 to 32 */
- result = (result & 0xffffffff) + (result >> 32);
- return result;
-}
-
-/*
- * Do a 64-bit checksum on an arbitrary memory area..
- *
- * This isn't a great routine, but it's not _horrible_ either. The
- * inner loop could be unrolled a bit further, and there are better
- * ways to do the carry, but this is reasonable.
- */
-static inline unsigned long do_csum(const unsigned char * buff, int len)
-{
- int odd, count;
- unsigned long long result = 0;
-
- if (len <= 0)
- goto out;
- odd = 1 & (unsigned long) buff;
- if (odd) {
- result = *buff << 8;
- len--;
- buff++;
- }
- count = len >> 1; /* nr of 16-bit words.. */
- if (count) {
- if (2 & (unsigned long) buff) {
- result += *(unsigned short *) buff;
- count--;
- len -= 2;
- buff += 2;
- }
- count >>= 1; /* nr of 32-bit words.. */
- if (count) {
- if (4 & (unsigned long) buff) {
- result += *(unsigned int *) buff;
- count--;
- len -= 4;
- buff += 4;
- }
- count >>= 1; /* nr of 64-bit words.. */
- if (count) {
- unsigned long carry = 0;
- do {
- unsigned long w = *(unsigned long *) buff;
- count--;
- buff += 8;
- result += carry;
- result += w;
- carry = (w > result);
- } while (count);
- result += carry;
- result = (result & 0xffffffff) + (result >> 32);
- }
- if (len & 4) {
- result += *(unsigned int *) buff;
- buff += 4;
- }
- }
- if (len & 2) {
- result += *(unsigned short *) buff;
- buff += 2;
- }
- }
- if (len & 1)
- result += *buff;
- result = from64to16(result);
- if (odd)
- result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-out:
- return result;
-}
-
-/*
- * This is a version of ip_compute_csum() optimized for IP headers,
- * which always checksum on 4 octet boundaries.
- */
-unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
-{
- return ~do_csum(iph,ihl*4);
-}
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
-{
- unsigned long long result = do_csum(buff, len);
-
- /* add in old sum, and carry.. */
- result += sum;
- /* 32+c bits -> 32 bits */
- result = (result & 0xffffffff) + (result >> 32);
- return result;
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-unsigned short ip_compute_csum(unsigned char * buff, int len)
-{
- return ~from64to16(do_csum(buff,len));
-}
+++ /dev/null
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * MIPS specific IP/TCP/UDP checksumming routines
- *
- * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de>
- * Lots of code moved from tcp.c and ip.c; see those files
- * for more names.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * $Id: csum_partial_copy.c,v 1.2 1998/09/16 13:29:32 ralf Exp $
- */
-#include <net/checksum.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-#include <asm/string.h>
-#include <asm/uaccess.h>
-
-/*
- * copy while checksumming, otherwise like csum_partial
- */
-unsigned int csum_partial_copy(const char *src, char *dst,
- int len, unsigned int sum)
-{
- /*
- * It's 2:30 am and I don't feel like doing it real ...
- * This is lots slower than the real thing (tm)
- */
- sum = csum_partial(src, len, sum);
- memcpy(dst, src, len);
-
- return sum;
-}
-
-/*
- * Copy from userspace and compute checksum. If we catch an exception
- * then zero the rest of the buffer.
- */
-unsigned int csum_partial_copy_from_user (const char *src, char *dst,
- int len, unsigned int sum,
- int *err_ptr)
-{
- int missing;
-
- missing = copy_from_user(dst, src, len);
- if (missing) {
- memset(dst + len - missing, 0, missing);
- *err_ptr = -EFAULT;
- }
-
- return csum_partial(dst, len, sum);
-}
-
-/*
- * Copy to userspace and compute checksum.
- */
-unsigned int csum_partial_copy_to_user (const char *src, char *dst,
- int len, unsigned int sum,
- int *err_ptr)
-{
- sum = csum_partial(src, len, sum);
-
- if (copy_to_user(dst, src, len)) {
- *err_ptr = -EFAULT;
- return sum;
- }
-
- return sum;
-}
-! Taken from newlib-1.8.0
+/* $Id: memcpy.S,v 1.3 1999/09/28 11:32:48 gniibe Exp $
+ *
+ * "memcpy" implementation of SuperH
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ *
+ */
-!
-! Fast SH memcpy
-!
-! by Toshiyasu Morita (tm@netcom.com)
-! hacked by J"orn Rernnecke (amylaar@cygnus.co.uk) ("o for o-umlaut)
-!
-! Entry: r4: destination pointer
-! r5: source pointer
-! r6: byte count
-!
-! Exit: r0: destination pointer
-! r1-r7: trashed
-!
-! Notes: Usually one wants to do small reads and write a longword, but
-! unfortunately it is difficult in some cases to concatanate bytes
-! into a longword on the SH, so this does a longword read and small
-! writes.
-!
-! This implementation makes two assumptions about how it is called:
-!
-! 1.: If the byte count is nonzero, the address of the last byte to be
-! copied is unsigned greater than the address of the first byte to
-! be copied. This could be easily swapped for a signed comparison,
-! but the algorithm used needs some comparison.
-!
-! 2.: When there are two or three bytes in the last word of an 11-or-bore
-! bytes memory chunk to b copied, the rest of the word can be read
-! without size effects.
-! This could be easily changed by increasing the minumum size of
-! a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2,
-! however, this would cost a few extra cyles on average.
-!
+/*
+ * void *memcpy(void *dst, const void *src, size_t n);
+ * No overlap between the memory of DST and of SRC are assumed.
+ */
#include <linux/linkage.h>
ENTRY(memcpy)
- ! Big endian version copies with decreasing addresses.
- mov r4,r0
- add r6,r0
- sub r4,r5
- mov #11,r1
- cmp/hs r1,r6
- bf/s L_small
+ tst r6,r6
+ bt/s 9f ! if n=0, do nothing
+ mov r4,r0
+ sub r4,r5 ! From here, r5 has the distance to r0
+ add r6,r0 ! From here, r0 points the end of copying point
+ mov #12,r1
+ cmp/gt r6,r1
+ bt/s 7f ! if it's too small, copy a byte at once
add #-1,r5
- mov r5,r3
- add r0,r3
- shlr r3
- bt/s L_even
- mov r4,r7
- mov.b @(r0,r5),r2
- add #-1,r3
- mov.b r2,@-r0
-L_even:
- tst #1,r0
- add #-1,r5
- bf/s L_odddst
- add #8,r7
- tst #2,r0
- bt L_al4dst
- add #-1,r3
- mov.w @(r0,r5),r1
- mov.w r1,@-r0
-L_al4dst:
- shlr r3
- bt L_al4both
- mov.w @(r0,r5),r1
- swap.w r1,r1
- add #4,r7
- add #-4,r5
- .align 2
-L_2l_loop:
- mov.l @(r0,r5),r2
- xtrct r2,r1
- mov.l r1,@-r0
- cmp/hs r7,r0
- mov.l @(r0,r5),r1
- xtrct r1,r2
- mov.l r2,@-r0
- bt L_2l_loop
- bra L_cleanup
- add #5,r5
+ add #1,r5
+ ! From here, r6 is free
+ !
+ ! r4 --> [ ... ] DST [ ... ] SRC
+ ! [ ... ] [ ... ]
+ ! : :
+ ! r0 --> [ ... ] r0+r5 --> [ ... ]
+ !
+ !
+ mov r5,r1
+ mov #3,r2
+ and r2,r1
+ shll2 r1
+ mov r0,r3 ! Save the value on R0 to R3
+ mova jmptable,r0
+ add r1,r0
+ mov.l @r0,r1
+ jmp @r1
+ mov r3,r0 ! and back to R0
+ .balign 4
+jmptable:
+ .long case0
+ .long case1
+ .long case2
+ .long case3
- nop ! avoid nop in executed code.
-L_al4both:
- add #-2,r5
- .align 2
-L_al4both_loop:
- mov.l @(r0,r5),r1
- cmp/hs r7,r0
- bt/s L_al4both_loop
+ ! copy a byte at once
+7: mov r4,r2
+ add #1,r2
+8:
+ cmp/hi r2,r0
+ mov.b @(r0,r5),r1
+ bt/s 8b ! while (r0>r2)
+ mov.b r1,@-r0
+9:
+ rts
+ nop
+
+case0:
+ !
+ ! GHIJ KLMN OPQR --> GHIJ KLMN OPQR
+ !
+ ! First, align to long word boundary
+ mov r0,r3
+ and r2,r3
+ tst r3,r3
+ bt/s 2f
+ add #-4,r5
+ add #3,r5
+1: dt r3
+ mov.b @(r0,r5),r1
+ bf/s 1b
+ mov.b r1,@-r0
+ !
+ add #-3,r5
+2: ! Second, copy a long word at once
+ mov r4,r2
+ add #7,r2
+3: mov.l @(r0,r5),r1
+ cmp/hi r2,r0
+ bt/s 3b
mov.l r1,@-r0
- bra L_cleanup
+ !
+ ! Third, copy a byte at once, if necessary
+ cmp/eq r4,r0
+ bt/s 9b
add #3,r5
+ bra 8b
+ add #-6,r2
- nop ! avoid nop in executed code.
-L_odddst:
- shlr r3
- bt L_al4src
- mov.w @(r0,r5),r1
- mov.b r1,@-r0
- shlr8 r1
- mov.b r1,@-r0
-L_al4src:
- add #-2,r5
- .align 2
-L_odd_loop:
- mov.l @(r0,r5),r2
- cmp/hs r7,r0
- mov.b r2,@-r0
- shlr8 r2
- mov.w r2,@-r0
- shlr16 r2
- mov.b r2,@-r0
- bt L_odd_loop
-
- add #3,r5
-L_cleanup:
-L_small:
+case1:
+ !
+ ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR.
+ !
+ ! First, align to long word boundary
+ mov r0,r3
+ and r2,r3
+ tst r3,r3
+ bt/s 2f
+ add #-1,r5
+1: dt r3
+ mov.b @(r0,r5),r1
+ bf/s 1b
+ mov.b r1,@-r0
+ !
+2: ! Second, read a long word and write a long word at once
+ mov.l @(r0,r5),r1
+ add #-4,r5
+ mov r4,r2
+ add #7,r2
+ !
+#ifdef __LITTLE_ENDIAN__
+3: mov r1,r3 ! RQPO
+ shll16 r3
+ shll8 r3 ! Oxxx
+ mov.l @(r0,r5),r1 ! NMLK
+ mov r1,r6
+ shlr8 r6 ! xNML
+ or r6,r3 ! ONML
+ cmp/hi r2,r0
+ bt/s 3b
+ mov.l r3,@-r0
+#else
+3: mov r1,r3 ! OPQR
+ shlr16 r3
+ shlr8 r3 ! xxxO
+ mov.l @(r0,r5),r1 ! KLMN
+ mov r1,r6
+ shll8 r6 ! LMNx
+ or r6,r3 ! LMNO
+ cmp/hi r2,r0
+ bt/s 3b
+ mov.l r3,@-r0
+#endif
+ !
+ ! Third, copy a byte at once, if necessary
cmp/eq r4,r0
- bt L_ready
- add #1,r4
- .align 2
-L_cleanup_loop:
- mov.b @(r0,r5),r2
+ bt/s 9b
+ add #4,r5
+ bra 8b
+ add #-6,r2
+
+case2:
+ !
+ ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR..
+ !
+ ! First, align to word boundary
+ tst #1,r0
+ bt/s 2f
+ add #-1,r5
+ mov.b @(r0,r5),r1
+ mov.b r1,@-r0
+ !
+2: ! Second, read a word and write a word at once
+ add #-1,r5
+ mov r4,r2
+ add #3,r2
+ !
+3: mov.w @(r0,r5),r1
+ cmp/hi r2,r0
+ bt/s 3b
+ mov.w r1,@-r0
+ !
+ ! Third, copy a byte at once, if necessary
cmp/eq r4,r0
- mov.b r2,@-r0
- bf L_cleanup_loop
-L_ready:
+ bt/s 9b
+ add #1,r5
+ mov.b @(r0,r5),r1
rts
- nop
+ mov.b r1,@-r0
+
+case3:
+ !
+ ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R...
+ !
+ ! First, align to long word boundary
+ mov r0,r3
+ and r2,r3
+ tst r3,r3
+ bt/s 2f
+ add #-1,r5
+1: dt r3
+ mov.b @(r0,r5),r1
+ bf/s 1b
+ mov.b r1,@-r0
+ !
+2: ! Second, read a long word and write a long word at once
+ add #-2,r5
+ mov.l @(r0,r5),r1
+ add #-4,r5
+ mov r4,r2
+ add #7,r2
+ !
+#ifdef __LITTLE_ENDIAN__
+3: mov r1,r3 ! RQPO
+ shll8 r3 ! QPOx
+ mov.l @(r0,r5),r1 ! NMLK
+ mov r1,r6
+ shlr16 r6
+ shlr8 r6 ! xxxN
+ or r6,r3 ! QPON
+ cmp/hi r2,r0
+ bt/s 3b
+ mov.l r3,@-r0
+#else
+3: mov r1,r3 ! OPQR
+ shlr8 r3 ! xOPQ
+ mov.l @(r0,r5),r1 ! KLMN
+ mov r1,r6
+ shll16 r6
+ shll8 r6 ! Nxxx
+ or r6,r3 ! NOPQ
+ cmp/hi r2,r0
+ bt/s 3b
+ mov.l r3,@-r0
+#endif
+ !
+ ! Third, copy a byte at once, if necessary
+ cmp/eq r4,r0
+ bt/s 9b
+ add #6,r5
+ bra 8b
+ add #-6,r2
+/* $Id: memmove.S,v 1.2 1999/09/21 12:55:49 gniibe Exp $
+ *
+ * "memmove" implementation of SuperH
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ *
+ */
+
+/*
+ * void *memmove(void *dst, const void *src, size_t n);
+ * The memory areas may overlap.
+ */
+
#include <linux/linkage.h>
ENTRY(memmove)
- mov.l r8,@-r15
- mov.l r9,@-r15
- mov.l r14,@-r15
- sts.l pr,@-r15
- add #-28,r15
- mov r15,r14
- mov.l r4,@r14
- mov.l r5,@(4,r14)
- mov.l r6,@(8,r14)
- mov.l @r14,r1
- mov.l r1,@(12,r14)
- mov.l @(4,r14),r1
- mov.l r1,@(16,r14)
- mov.l @(12,r14),r1
- mov.l @(16,r14),r2
- sub r2,r1
- mov.l @(8,r14),r2
- cmp/hs r2,r1
- bt .L54
- bra .L2
- nop
-.L54:
- mov.l @(8,r14),r1
- mov #15,r2
- cmp/gt r2,r1
- bt .LF100
- bra .L52
- nop
-.LF100:
- mov.l @(12,r14),r2
- neg r2,r1
- mov #3,r2
- and r1,r2
- mov.l @(8,r14),r1
- mov r1,r9
- sub r2,r9
- mov r9,r2
- mov.l r2,@(8,r14)
-.L4:
- mov.l @(12,r14),r2
- neg r2,r1
- mov #3,r2
- and r1,r2
- mov.l r2,@(20,r14)
-.L7:
- mov.l @(20,r14),r1
- cmp/pl r1
- bt .L9
- bra .L6
- nop
- .align 2
-.L9:
- mov r14,r2
- mov r14,r1
- add #24,r1
- mov.l @(16,r14),r2
- mov.b @r2,r3
- mov.b r3,@r1
- mov.l @(16,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(16,r14)
- mov.l @(20,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(20,r14)
- mov.l @(12,r14),r1
- mov r14,r2
- mov r14,r3
- add #24,r3
- mov.b @r3,r2
- mov.b r2,@r1
- mov.l @(12,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(12,r14)
- bra .L7
- nop
- .align 2
-.L8:
-.L6:
- bra .L5
- nop
- .align 2
-.L10:
- bra .L4
- nop
- .align 2
-.L5:
- nop
-.L11:
- mov.l @(16,r14),r1
+ ! if dest > src, call memcpy (it copies in decreasing order)
+ cmp/hi r5,r4
+ bf 1f
+ mov.l 2f,r0
+ jmp @r0
+ nop
+ .balign 4
+2: .long SYMBOL_NAME(memcpy)
+1:
+ sub r5,r4 ! From here, r4 has the distance to r0
+ tst r6,r6
+ bt/s 9f ! if n=0, do nothing
+ mov r5,r0
+ add r6,r5
+ mov #12,r1
+ cmp/gt r6,r1
+ bt/s 8f ! if it's too small, copy a byte at once
+ add #-1,r4
+ add #1,r4
+ !
+ ! [ ... ] DST [ ... ] SRC
+ ! [ ... ] [ ... ]
+ ! : :
+ ! r0+r4--> [ ... ] r0 --> [ ... ]
+ ! : :
+ ! [ ... ] [ ... ]
+ ! r5 -->
+ !
+ mov r4,r1
mov #3,r2
- and r1,r2
- tst r2,r2
- bf .L14
- mov r15,r2
- mov.l @(12,r14),r1
- mov.l @(16,r14),r2
- mov.l @(8,r14),r7
- mov r7,r3
- shlr2 r3
- mov r1,r4
- mov r2,r5
- mov r3,r6
- mov.l .L46,r8
- jsr @r8
- nop
- bra .L15
- nop
- .align 2
-.L14:
- mov r15,r2
- mov.l @(12,r14),r1
- mov.l @(16,r14),r2
- mov.l @(8,r14),r7
- mov r7,r3
- shlr2 r3
- mov r1,r4
- mov r2,r5
- mov r3,r6
- mov.l .L47,r8
- jsr @r8
- nop
-.L15:
- mov.l @(8,r14),r1
- mov #-4,r2
- and r2,r1
- mov.l @(16,r14),r2
- add r2,r1
- mov.l r1,@(16,r14)
- mov.l @(8,r14),r1
- mov #-4,r2
and r2,r1
- mov.l @(12,r14),r2
- add r2,r1
- mov.l r1,@(12,r14)
- mov.l @(8,r14),r1
- mov #3,r2
- and r1,r2
- mov.l r2,@(8,r14)
-.L13:
-.L52:
- bra .L3
- nop
- .align 2
-.L16:
- bra .L11
- nop
- .align 2
-.L12:
-.L3:
- nop
-.L17:
- mov.l @(8,r14),r1
- mov.l r1,@(20,r14)
-.L20:
- mov.l @(20,r14),r1
- cmp/pl r1
- bt .L22
- bra .L19
- nop
- .align 2
-.L22:
- mov r14,r2
- mov r14,r1
- add #24,r1
- mov.l @(16,r14),r2
- mov.b @r2,r3
- mov.b r3,@r1
- mov.l @(16,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(16,r14)
- mov.l @(20,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(20,r14)
- mov.l @(12,r14),r1
- mov r14,r2
- mov r14,r3
- add #24,r3
- mov.b @r3,r2
- mov.b r2,@r1
- mov.l @(12,r14),r1
+ shll2 r1
+ mov r0,r3 ! Save the value on R0 to R3
+ mova jmptable,r0
+ add r1,r0
+ mov.l @r0,r1
+ jmp @r1
+ mov r3,r0 ! and back to R0
+ .balign 4
+jmptable:
+ .long case0
+ .long case1
+ .long case2
+ .long case3
+
+ ! copy a byte at once
+8: mov.b @r0+,r1
+ cmp/hs r5,r0
+ bf/s 8b ! while (r0<r5)
+ mov.b r1,@(r0,r4)
+ add #1,r4
+9:
+ add r4,r0
+ rts
+ sub r6,r0
+
+case_none:
+ bra 8b
+ add #-1,r4
+
+case0:
+ !
+ ! GHIJ KLMN OPQR --> GHIJ KLMN OPQR
+ !
+ ! First, align to long word boundary
+ mov r0,r3
+ and r2,r3
+ tst r3,r3
+ bt/s 2f
+ add #-1,r4
+ mov #4,r2
+ sub r3,r2
+1: dt r2
+ mov.b @r0+,r1
+ bf/s 1b
+ mov.b r1,@(r0,r4)
+ !
+2: ! Second, copy a long word at once
+ add #-3,r4
+ add #-3,r5
+3: mov.l @r0+,r1
+ cmp/hs r5,r0
+ bf/s 3b
+ mov.l r1,@(r0,r4)
+ add #3,r5
+ !
+ ! Third, copy a byte at once, if necessary
+ cmp/eq r5,r0
+ bt/s 9b
+ add #4,r4
+ bra 8b
+ add #-1,r4
+
+case3:
+ !
+ ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR.
+ !
+ ! First, align to long word boundary
+ mov r0,r3
+ and r2,r3
+ tst r3,r3
+ bt/s 2f
+ add #-1,r4
+ mov #4,r2
+ sub r3,r2
+1: dt r2
+ mov.b @r0+,r1
+ bf/s 1b
+ mov.b r1,@(r0,r4)
+ !
+2: ! Second, read a long word and write a long word at once
+ add #-2,r4
+ mov.l @(r0,r4),r1
+ add #-7,r5
+ add #-4,r4
+ !
+#ifdef __LITTLE_ENDIAN__
+ shll8 r1
+3: mov r1,r3 ! JIHG
+ shlr8 r3 ! xJIH
+ mov.l @r0+,r1 ! NMLK
mov r1,r2
- add #1,r2
- mov.l r2,@(12,r14)
- bra .L20
- nop
- .align 2
-.L21:
-.L19:
- bra .L18
- nop
- .align 2
-.L23:
- bra .L17
- nop
- .align 2
-.L18:
- bra .L24
- nop
- .align 2
-.L2:
- mov.l @(16,r14),r1
- mov.l @(8,r14),r2
- add r2,r1
- mov.l r1,@(16,r14)
- mov.l @(12,r14),r1
- mov.l @(8,r14),r2
- add r2,r1
- mov.l r1,@(12,r14)
- mov.l @(8,r14),r1
- mov #15,r2
- cmp/gt r2,r1
- bt .LF101
- bra .L53
- nop
-.LF101:
- mov.l @(12,r14),r1
- mov #3,r2
- and r1,r2
- mov.l @(8,r14),r1
- mov r1,r9
- sub r2,r9
- mov r9,r2
- mov.l r2,@(8,r14)
-.L26:
- mov.l @(12,r14),r1
- mov #3,r2
- and r1,r2
- mov.l r2,@(20,r14)
-.L29:
- mov.l @(20,r14),r1
- cmp/pl r1
- bt .L31
- bra .L28
- nop
- .align 2
-.L31:
- mov.l @(16,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(16,r14)
- mov r14,r2
- mov r14,r1
- add #24,r1
- mov.l @(16,r14),r2
- mov.b @r2,r3
- mov.b r3,@r1
- mov.l @(12,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(12,r14)
- mov.l @(20,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(20,r14)
- mov.l @(12,r14),r1
- mov r14,r2
- mov r14,r3
- add #24,r3
- mov.b @r3,r2
- mov.b r2,@r1
- bra .L29
- nop
- .align 2
-.L30:
-.L28:
- bra .L27
- nop
- .align 2
-.L32:
- bra .L26
- nop
- .align 2
-.L27:
- nop
-.L33:
- mov.l @(16,r14),r1
- mov #3,r2
- and r1,r2
- tst r2,r2
- bf .L36
- mov r15,r2
- mov.l @(12,r14),r1
- mov.l @(16,r14),r2
- mov.l @(8,r14),r7
- mov r7,r3
- shlr2 r3
- mov r1,r4
- mov r2,r5
- mov r3,r6
- mov.l .L48,r8
- jsr @r8
- nop
- bra .L37
- nop
- .align 2
-.L36:
- mov r15,r2
- mov.l @(12,r14),r1
- mov.l @(16,r14),r2
- mov.l @(8,r14),r7
- mov r7,r3
- shlr2 r3
- mov r1,r4
- mov r2,r5
- mov r3,r6
- mov.l .L49,r8
- jsr @r8
- nop
-.L37:
- mov.l @(8,r14),r1
- mov #-4,r2
- and r2,r1
- mov.l @(16,r14),r2
- mov r2,r9
- sub r1,r9
- mov r9,r1
- mov.l r1,@(16,r14)
- mov.l @(8,r14),r1
- mov #-4,r2
- and r2,r1
- mov.l @(12,r14),r2
- mov r2,r9
- sub r1,r9
- mov r9,r1
- mov.l r1,@(12,r14)
- mov.l @(8,r14),r1
- mov #3,r2
- and r1,r2
- mov.l r2,@(8,r14)
-.L35:
-.L53:
- bra .L25
- nop
- .align 2
-.L38:
- bra .L33
- nop
- .align 2
-.L34:
-.L25:
- nop
-.L39:
- mov.l @(8,r14),r1
- mov.l r1,@(20,r14)
-.L42:
- mov.l @(20,r14),r1
- cmp/pl r1
- bt .L44
- bra .L41
- nop
- .align 2
-.L44:
- mov.l @(16,r14),r1
+ shll16 r2
+ shll8 r2 ! Kxxx
+ or r2,r3 ! KJIH
+ cmp/hs r5,r0
+ bf/s 3b
+ mov.l r3,@(r0,r4)
+#else
+ shlr8 r1
+3: mov r1,r3 ! GHIJ
+ shll8 r3 ! HIJx
+ mov.l @r0+,r1 ! KLMN
mov r1,r2
- add #-1,r2
- mov.l r2,@(16,r14)
- mov r14,r2
- mov r14,r1
- add #24,r1
- mov.l @(16,r14),r2
- mov.b @r2,r3
- mov.b r3,@r1
- mov.l @(12,r14),r1
+ shlr16 r2
+ shlr8 r2 ! xxxK
+ or r2,r3 ! HIJK
+ cmp/hs r5,r0
+ bf/s 3b
+ mov.l r3,@(r0,r4)
+#endif
+ add #7,r5
+ !
+ ! Third, copy a byte at once, if necessary
+ cmp/eq r5,r0
+ bt/s 9b
+ add #7,r4
+ add #-3,r0
+ bra 8b
+ add #-1,r4
+
+case2:
+ !
+ ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR..
+ !
+ ! First, align to word boundary
+ tst #1,r0
+ bt/s 2f
+ add #-1,r4
+ mov.b @r0+,r1
+ mov.b r1,@(r0,r4)
+ !
+2: ! Second, read a word and write a word at once
+ add #-1,r4
+ add #-1,r5
+ !
+3: mov.w @r0+,r1
+ cmp/hs r5,r0
+ bf/s 3b
+ mov.w r1,@(r0,r4)
+ add #1,r5
+ !
+ ! Third, copy a byte at once, if necessary
+ cmp/eq r5,r0
+ bt/s 9b
+ add #2,r4
+ mov.b @r0,r1
+ mov.b r1,@(r0,r4)
+ bra 9b
+ add #1,r0
+
+case1:
+ !
+ ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R...
+ !
+ ! First, align to long word boundary
+ mov r0,r3
+ and r2,r3
+ tst r3,r3
+ bt/s 2f
+ add #-1,r4
+ mov #4,r2
+ sub r3,r2
+1: dt r2
+ mov.b @r0+,r1
+ bf/s 1b
+ mov.b r1,@(r0,r4)
+ !
+2: ! Second, read a long word and write a long word at once
+ mov.l @(r0,r4),r1
+ add #-7,r5
+ add #-4,r4
+ !
+#ifdef __LITTLE_ENDIAN__
+ shll16 r1
+ shll8 r1
+3: mov r1,r3 ! JIHG
+ shlr16 r3
+ shlr8 r3 ! xxxJ
+ mov.l @r0+,r1 ! NMLK
mov r1,r2
- add #-1,r2
- mov.l r2,@(12,r14)
- mov.l @(20,r14),r1
+ shll8 r2 ! MLKx
+ or r2,r3 ! MLKJ
+ cmp/hs r5,r0
+ bf/s 3b
+ mov.l r3,@(r0,r4)
+#else
+ shlr16 r1
+ shlr8 r1
+3: mov r1,r3 ! GHIJ
+ shll16 r3
+ shll8 r3 ! Jxxx
+ mov.l @r0+,r1 ! KLMN
mov r1,r2
- add #-1,r2
- mov.l r2,@(20,r14)
- mov.l @(12,r14),r1
- mov r14,r2
- mov r14,r3
- add #24,r3
- mov.b @r3,r2
- mov.b r2,@r1
- bra .L42
- nop
- .align 2
-.L43:
-.L41:
- bra .L24
- nop
- .align 2
-.L45:
- bra .L39
- nop
- .align 2
-.L40:
-.L24:
- mov.l @r14,r1
- mov r1,r0
- bra .L1
- nop
- .align 2
-.L1:
- add #28,r14
- mov r14,r15
- lds.l @r15+,pr
- mov.l @r15+,r14
- mov.l @r15+,r9
- mov.l @r15+,r8
- rts
- nop
-.L50:
- .align 2
-.L46:
- .long __wordcopy_fwd_aligned
-.L47:
- .long __wordcopy_fwd_dest_aligned
-.L48:
- .long __wordcopy_bwd_aligned
-.L49:
- .long __wordcopy_bwd_dest_aligned
-.Lfe1:
+ shlr8 r2 ! xKLM
+ or r2,r3 ! JKLM
+ cmp/hs r5,r0
+ bf/s 3b ! while(r0<r5)
+ mov.l r3,@(r0,r4)
+#endif
+ add #7,r5
+ !
+ ! Third, copy a byte at once, if necessary
+ cmp/eq r5,r0
+ bt/s 9b
+ add #5,r4
+ add #-3,r0
+ bra 8b
+ add #-1,r4
-! Taken from newlib-1.8.0
+/* $Id: memset.S,v 1.1 1999/09/18 16:57:09 gniibe Exp $
+ *
+ * "memset" implementation of SuperH
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ *
+ */
+
+/*
+ * void *memset(void *s, int c, size_t n);
+ */
-!
-! Fast SH memset
-!
-! by Toshiyasu Morita (tm@netcom.com)
-!
-! Entry: r4: destination pointer
-! r5: fill value
-! r6: byte count
-!
-! Exit: r0-r3: trashed
-!
#include <linux/linkage.h>
ENTRY(memset)
- mov r4,r3 ! Save return value
-
- mov r6,r0 ! Check explicitly for zero
- cmp/eq #0,r0
- bt L_exit
-
- mov #12,r0 ! Check for small number of bytes
+ tst r6,r6
+ bt/s 5f ! if n=0, do nothing
+ add r6,r4
+ mov #12,r0
cmp/gt r6,r0
- bt L_store_byte_loop
-
- neg r4,r0 ! Align destination
- add #4,r0
+ bt/s 4f ! if it's too small, set a byte at once
+ mov r4,r0
and #3,r0
- tst r0,r0
- bt L_dup_bytes
- .balignw 4,0x0009
-L_align_loop:
- mov.b r5,@r4
- add #-1,r6
- add #1,r4
+ cmp/eq #0,r0
+ bt/s 2f ! It's aligned
+ sub r0,r6
+1:
dt r0
- bf L_align_loop
-
-L_dup_bytes:
- extu.b r5,r5 ! Duplicate bytes across longword
- swap.b r5,r0
- or r0,r5
- swap.w r5,r0
- or r0,r5
-
- mov r6,r2 ! Calculate number of double longwords
- shlr2 r2
- shlr r2
-
- .balignw 4,0x0009
-L_store_long_loop:
- mov.l r5,@r4 ! Store double longs to memory
- dt r2
- mov.l r5,@(4,r4)
- add #8,r4
- bf L_store_long_loop
-
+ bf/s 1b
+ mov.b r5,@-r4
+2: ! make VVVV
+ swap.b r5,r0 ! V0
+ or r0,r5 ! VV
+ swap.w r5,r0 ! VV00
+ or r0,r5 ! VVVV
+ !
+ mov r6,r0
+ shlr2 r0
+ shlr r0 ! r0 = r6 >> 3
+3:
+ dt r0
+ mov.l r5,@-r4 ! set 8-byte at once
+ bf/s 3b
+ mov.l r5,@-r4
+ !
mov #7,r0
and r0,r6
tst r6,r6
- bt L_exit
- .balignw 4,0x0009
-L_store_byte_loop:
- mov.b r5,@r4 ! Store bytes to memory
- add #1,r4
+ bt 5f
+ ! fill bytes
+4:
dt r6
- bf L_store_byte_loop
-
-L_exit:
+ bf/s 4b
+ mov.b r5,@-r4
+5:
rts
- mov r3,r0
+ mov r4,r0
+++ /dev/null
-#include <linux/linkage.h>
-ENTRY(_wordcopy_fwd_aligned)
- mov.l r14,@-r15
- add #-20,r15
- mov r15,r14
- mov.l r4,@r14
- mov.l r5,@(4,r14)
- mov.l r6,@(8,r14)
- mov.l @(8,r14),r2
- mov #7,r1
- and r2,r1
- mov #0,r2
- mov #7,r3
- sub r2,r1
- cmp/hi r3,r1
- bf .L29
- bra .L2
- nop
-.L29:
- mova .L22,r0
- add r1,r1
- mov.w @(r0,r1),r1
- add r0,r1
- jmp @r1
- nop
- .align 2
- .align 2
-.L22:
- .word .L15-.L22
- .word .L18-.L22
- .word .L3-.L22
- .word .L5-.L22
- .word .L7-.L22
- .word .L9-.L22
- .word .L11-.L22
- .word .L13-.L22
- .align 2
-.L3:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-24,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-28,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #6,r2
- mov.l r2,@(8,r14)
- bra .L4
- nop
- .align 2
-.L5:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-20,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-24,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #5,r2
- mov.l r2,@(8,r14)
- bra .L6
- nop
- .align 2
-.L7:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-20,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #4,r2
- mov.l r2,@(8,r14)
- bra .L8
- nop
- .align 2
-.L9:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #3,r2
- mov.l r2,@(8,r14)
- bra .L10
- nop
- .align 2
-.L11:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #2,r2
- mov.l r2,@(8,r14)
- bra .L12
- nop
- .align 2
-.L13:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(8,r14)
- bra .L14
- nop
- .align 2
-.L15:
- bra .L16
- nop
- bra .L1
- nop
- .align 2
-.L16:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@r14
- bra .L17
- nop
- .align 2
-.L18:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #4,r2
- mov.l r2,@(4,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(8,r14)
- bra .L19
- nop
- bra .L20
- nop
- .align 2
-.L19:
- bra .L21
- nop
- .align 2
-.L23:
-.L2:
- nop
-.L24:
-.L21:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L17:
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #4,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
-.L14:
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #8,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L12:
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #12,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
-.L10:
- mov.l @(4,r14),r2
- mov r2,r1
- add #16,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #16,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L8:
- mov.l @(4,r14),r2
- mov r2,r1
- add #20,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #20,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
-.L6:
- mov.l @(4,r14),r2
- mov r2,r1
- add #24,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #24,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L4:
- mov.l @(4,r14),r2
- mov r2,r1
- add #28,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #28,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
- mov.l @(4,r14),r1
- mov r1,r2
- add #32,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #32,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@(8,r14)
-.L26:
- mov.l @(8,r14),r1
- tst r1,r1
- bf .L27
- bra .L25
- nop
- .align 2
-.L27:
- bra .L21
- nop
- .align 2
-.L25:
- nop
-.L20:
- mov.l @r14,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L1:
- add #20,r14
- mov r14,r15
- mov.l @r15+,r14
- rts
- nop
-.Lfe1:
- .size __wordcopy_fwd_aligned,.Lfe1-__wordcopy_fwd_aligned
- .global ___lshrsi3
- .global ___ashlsi3
- .align 2
- .global __wordcopy_fwd_dest_aligned
- .type __wordcopy_fwd_dest_aligned,@function
-__wordcopy_fwd_dest_aligned:
- mov.l r8,@-r15
- mov.l r9,@-r15
- mov.l r14,@-r15
- sts.l pr,@-r15
- add #-40,r15
- mov r15,r14
- mov.l r4,@r14
- mov.l r5,@(4,r14)
- mov.l r6,@(8,r14)
- mov.l @(4,r14),r1
- mov #3,r2
- and r1,r2
- mov r2,r1
- mov r1,r2
- shll2 r2
- add r2,r2
- mov.l r2,@(28,r14)
- mov.l @(28,r14),r2
- neg r2,r1
- add #32,r1
- mov.l r1,@(32,r14)
- mov.l @(4,r14),r1
- mov #-4,r2
- and r2,r1
- mov.l r1,@(4,r14)
- mov.l @(8,r14),r2
- mov #3,r1
- and r2,r1
- mov #0,r2
- mov #3,r3
- sub r2,r1
- cmp/hi r3,r1
- bf .L53
- bra .L31
- nop
-.L53:
- mova .L43,r0
- add r1,r1
- mov.w @(r0,r1),r1
- add r0,r1
- jmp @r1
- nop
- .align 2
- .align 2
-.L43:
- .word .L36-.L43
- .word .L39-.L43
- .word .L32-.L43
- .word .L34-.L43
- .align 2
-.L32:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(20,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #2,r2
- mov.l r2,@(8,r14)
- bra .L33
- nop
- .align 2
-.L34:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(8,r14)
- bra .L35
- nop
- .align 2
-.L36:
- bra .L37
- nop
- bra .L30
- nop
- .align 2
-.L37:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(24,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #4,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@r14
- bra .L38
- nop
- .align 2
-.L39:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(20,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(24,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #8,r2
- mov.l r2,@(4,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(8,r14)
- bra .L40
- nop
- bra .L41
- nop
- .align 2
-.L40:
- bra .L42
- nop
- .align 2
-.L44:
-.L31:
- nop
-.L45:
-.L42:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r8
- mov.l .L49,r1
- mov.l @(20,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L50,r1
- mov.l @(24,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L38:
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r1
- mov r1,r8
- add #4,r8
- mov.l .L49,r1
- mov.l @(24,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L50,r1
- mov.l @(12,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L35:
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(20,r14)
- mov.l @r14,r1
- mov r1,r8
- add #8,r8
- mov.l .L49,r1
- mov.l @(12,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L50,r1
- mov.l @(16,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L33:
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(24,r14)
- mov.l @r14,r1
- mov r1,r8
- add #12,r8
- mov.l .L49,r1
- mov.l @(16,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L50,r1
- mov.l @(20,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
- mov.l @(4,r14),r1
- mov r1,r2
- add #16,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #16,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@(8,r14)
-.L47:
- mov.l @(8,r14),r1
- tst r1,r1
- bf .L48
- bra .L46
- nop
- .align 2
-.L48:
- bra .L42
- nop
- .align 2
-.L46:
- nop
-.L41:
- mov.l @r14,r8
- mov.l .L49,r1
- mov.l @(20,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L50,r1
- mov.l @(24,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L30:
- add #40,r14
- mov r14,r15
- lds.l @r15+,pr
- mov.l @r15+,r14
- mov.l @r15+,r9
- mov.l @r15+,r8
- rts
- nop
-.L51:
- .align 2
-.L49:
- .long ___lshrsi3
-.L50:
- .long ___ashlsi3
-.Lfe2:
- .size __wordcopy_fwd_dest_aligned,.Lfe2-__wordcopy_fwd_dest_aligned
- .align 2
- .global __wordcopy_bwd_aligned
- .type __wordcopy_bwd_aligned,@function
-__wordcopy_bwd_aligned:
- mov.l r14,@-r15
- add #-20,r15
- mov r15,r14
- mov.l r4,@r14
- mov.l r5,@(4,r14)
- mov.l r6,@(8,r14)
- mov.l @(8,r14),r2
- mov #7,r1
- and r2,r1
- mov #0,r2
- mov #7,r3
- sub r2,r1
- cmp/hi r3,r1
- bf .L82
- bra .L55
- nop
-.L82:
- mova .L75,r0
- add r1,r1
- mov.w @(r0,r1),r1
- add r0,r1
- jmp @r1
- nop
- .align 2
- .align 2
-.L75:
- .word .L68-.L75
- .word .L71-.L75
- .word .L56-.L75
- .word .L58-.L75
- .word .L60-.L75
- .word .L62-.L75
- .word .L64-.L75
- .word .L66-.L75
- .align 2
-.L56:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #6,r2
- mov.l r2,@(8,r14)
- bra .L57
- nop
- .align 2
-.L58:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #5,r2
- mov.l r2,@(8,r14)
- bra .L59
- nop
- .align 2
-.L60:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #4,r2
- mov.l r2,@(8,r14)
- bra .L61
- nop
- .align 2
-.L62:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-20,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #16,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #3,r2
- mov.l r2,@(8,r14)
- bra .L63
- nop
- .align 2
-.L64:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-24,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-20,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #20,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #2,r2
- mov.l r2,@(8,r14)
- bra .L65
- nop
- .align 2
-.L66:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-28,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-24,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #24,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(8,r14)
- bra .L67
- nop
- .align 2
-.L68:
- bra .L69
- nop
- bra .L54
- nop
- .align 2
-.L69:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-32,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-28,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #28,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- bra .L70
- nop
- .align 2
-.L71:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-36,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-32,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #32,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(8,r14)
- bra .L72
- nop
- bra .L73
- nop
- .align 2
-.L72:
- bra .L74
- nop
- .align 2
-.L76:
-.L55:
- nop
-.L77:
-.L74:
- mov.l @(4,r14),r2
- mov r2,r1
- add #28,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #28,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L70:
- mov.l @(4,r14),r2
- mov r2,r1
- add #24,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #24,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
-.L67:
- mov.l @(4,r14),r2
- mov r2,r1
- add #20,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #20,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L65:
- mov.l @(4,r14),r2
- mov r2,r1
- add #16,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #16,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
-.L63:
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #12,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L61:
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r2
- mov r2,r1
- add #8,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
-.L59:
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r2
- mov r2,r1
- add #4,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L57:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r1
- mov.l @(12,r14),r2
- mov.l r2,@r1
- mov.l @(4,r14),r1
- mov r1,r2
- add #-32,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-32,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@(8,r14)
-.L79:
- mov.l @(8,r14),r1
- tst r1,r1
- bf .L80
- bra .L78
- nop
- .align 2
-.L80:
- bra .L74
- nop
- .align 2
-.L78:
- nop
-.L73:
- mov.l @r14,r2
- mov r2,r1
- add #28,r1
- mov.l @(16,r14),r2
- mov.l r2,@r1
-.L54:
- add #20,r14
- mov r14,r15
- mov.l @r15+,r14
- rts
- nop
-.Lfe3:
- .size __wordcopy_bwd_aligned,.Lfe3-__wordcopy_bwd_aligned
- .align 2
- .global __wordcopy_bwd_dest_aligned
- .type __wordcopy_bwd_dest_aligned,@function
-__wordcopy_bwd_dest_aligned:
- mov.l r8,@-r15
- mov.l r9,@-r15
- mov.l r14,@-r15
- sts.l pr,@-r15
- add #-40,r15
- mov r15,r14
- mov.l r4,@r14
- mov.l r5,@(4,r14)
- mov.l r6,@(8,r14)
- mov.l @(4,r14),r1
- mov #3,r2
- and r1,r2
- mov r2,r1
- mov r1,r2
- shll2 r2
- add r2,r2
- mov.l r2,@(28,r14)
- mov.l @(28,r14),r2
- neg r2,r1
- add #32,r1
- mov.l r1,@(32,r14)
- mov.l @(4,r14),r1
- mov #-4,r2
- and r2,r1
- mov.l r1,@(4,r14)
- mov.l @(4,r14),r1
- mov r1,r2
- add #4,r2
- mov.l r2,@(4,r14)
- mov.l @(8,r14),r2
- mov #3,r1
- and r2,r1
- mov #0,r2
- mov #3,r3
- sub r2,r1
- cmp/hi r3,r1
- bf .L106
- bra .L84
- nop
-.L106:
- mova .L96,r0
- add r1,r1
- mov.w @(r0,r1),r1
- add r0,r1
- jmp @r1
- nop
- .align 2
- .align 2
-.L96:
- .word .L89-.L96
- .word .L92-.L96
- .word .L85-.L96
- .word .L87-.L96
- .align 2
-.L85:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(20,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #2,r2
- mov.l r2,@(8,r14)
- bra .L86
- nop
- .align 2
-.L87:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-8,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(24,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(20,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #1,r2
- mov.l r2,@(8,r14)
- bra .L88
- nop
- .align 2
-.L89:
- bra .L90
- nop
- bra .L83
- nop
- .align 2
-.L90:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-20,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-12,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #16,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(24,r14)
- bra .L91
- nop
- .align 2
-.L92:
- mov.l @(4,r14),r1
- mov r1,r2
- add #-24,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@r14
- mov.l @(4,r14),r2
- mov r2,r1
- add #20,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @(4,r14),r2
- mov r2,r1
- add #16,r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @(8,r14),r1
- mov r1,r2
- add #-1,r2
- mov.l r2,@(8,r14)
- bra .L93
- nop
- bra .L94
- nop
- .align 2
-.L93:
- bra .L95
- nop
- .align 2
-.L97:
-.L84:
- nop
-.L98:
-.L95:
- mov.l @(4,r14),r2
- mov r2,r1
- add #12,r1
- mov.l @r1,r2
- mov.l r2,@(24,r14)
- mov.l @r14,r1
- mov r1,r8
- add #12,r8
- mov.l .L102,r1
- mov.l @(12,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L103,r1
- mov.l @(16,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L91:
- mov.l @(4,r14),r2
- mov r2,r1
- add #8,r1
- mov.l @r1,r2
- mov.l r2,@(20,r14)
- mov.l @r14,r1
- mov r1,r8
- add #8,r8
- mov.l .L102,r1
- mov.l @(24,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L103,r1
- mov.l @(12,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L88:
- mov.l @(4,r14),r2
- mov r2,r1
- add #4,r1
- mov.l @r1,r2
- mov.l r2,@(16,r14)
- mov.l @r14,r1
- mov r1,r8
- add #4,r8
- mov.l .L102,r1
- mov.l @(20,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L103,r1
- mov.l @(24,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L86:
- mov.l @(4,r14),r1
- mov.l @r1,r2
- mov.l r2,@(12,r14)
- mov.l @r14,r8
- mov.l .L102,r1
- mov.l @(16,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L103,r1
- mov.l @(20,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
- mov.l @(4,r14),r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@(4,r14)
- mov.l @r14,r1
- mov r1,r2
- add #-16,r2
- mov.l r2,@r14
- mov.l @(8,r14),r1
- mov r1,r2
- add #-4,r2
- mov.l r2,@(8,r14)
-.L100:
- mov.l @(8,r14),r1
- tst r1,r1
- bf .L101
- bra .L99
- nop
- .align 2
-.L101:
- bra .L95
- nop
- .align 2
-.L99:
- nop
-.L94:
- mov.l @r14,r1
- mov r1,r8
- add #12,r8
- mov.l .L102,r1
- mov.l @(12,r14),r4
- mov.l @(28,r14),r5
- jsr @r1
- nop
- mov r0,r9
- mov.l .L103,r1
- mov.l @(16,r14),r4
- mov.l @(32,r14),r5
- jsr @r1
- nop
- mov.l r0,@(36,r14)
- mov.l @(36,r14),r1
- or r9,r1
- mov.l r1,@r8
-.L83:
- add #40,r14
- mov r14,r15
- lds.l @r15+,pr
- mov.l @r15+,r14
- mov.l @r15+,r9
- mov.l @r15+,r8
- rts
- nop
-.L104:
- .align 2
-.L102:
- .long ___lshrsi3
-.L103:
- .long ___ashlsi3
-.Lfe4:
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o
-O_OBJS := init.o fault.o ioremap.o extable.o
+O_OBJS := init.o fault.o ioremap.o extable.o cache.o
include $(TOPDIR)/Rules.make
--- /dev/null
+/* $Id: cache.c,v 1.7 1999/09/23 11:43:07 gniibe Exp $
+ *
+ * linux/arch/sh/mm/cache.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#if defined(__sh3__)
+#define CCR 0xffffffec /* Address of Cache Control Register */
+#define CCR_CACHE_VAL 0x00000005 /* 8k-byte cache, P1-wb, enable */
+#define CCR_CACHE_INIT 0x0000000d /* 8k-byte cache, CF, P1-wb, enable */
+#define CCR_CACHE_ENABLE 1
+
+#define CACHE_IC_ADDRESS_ARRAY 0xf0000000 /* SH-3 has unified cache system */
+#define CACHE_OC_ADDRESS_ARRAY 0xf0000000
+#define CACHE_VALID 1
+#define CACHE_UPDATED 2
+
+/* 7709A/7729 has 16K cache (256-entry), while 7702 has only 2K(direct)
+ 7702 is not supported (yet) */
+struct _cache_system_info {
+ int way_shift;
+ int entry_mask;
+ int num_entries;
+};
+
+static struct _cache_system_info cache_system_info;
+
+#define CACHE_OC_WAY_SHIFT (cache_system_info.way_shift)
+#define CACHE_IC_WAY_SHIFT (cache_system_info.way_shift)
+#define CACHE_OC_ENTRY_SHIFT 4
+#define CACHE_OC_ENTRY_MASK (cache_system_info.entry_mask)
+#define CACHE_IC_ENTRY_MASK (cache_system_info.entry_mask)
+#define CACHE_OC_NUM_ENTRIES (cache_system_info.num_entries)
+#define CACHE_OC_NUM_WAYS 4
+#define CACHE_IC_NUM_WAYS 4
+#elif defined(__SH4__)
+#define CCR 0xff00001c /* Address of Cache Control Register */
+#define CCR_CACHE_VAL 0x00000105 /* 8k+16k-byte cache,P1-wb,enable */
+#define CCR_CACHE_INIT 0x0000090d /* 8k+16k-byte cache,CF,P1-wb,enable */
+#define CCR_CACHE_ENABLE 0x00000101
+
+#define CACHE_IC_ADDRESS_ARRAY 0xf0000000
+#define CACHE_OC_ADDRESS_ARRAY 0xf4000000
+#define CACHE_VALID 1
+#define CACHE_UPDATED 2
+
+#define CACHE_OC_WAY_SHIFT 13
+#define CACHE_IC_WAY_SHIFT 13
+#define CACHE_OC_ENTRY_SHIFT 5
+#define CACHE_OC_ENTRY_MASK 0x3fe0
+#define CACHE_IC_ENTRY_MASK 0x1fe0
+#define CACHE_OC_NUM_ENTRIES 512
+#define CACHE_OC_NUM_WAYS 1
+#define CACHE_IC_NUM_WAYS 1
+#endif
+
+#define jump_to_p2(__dummy) \
+ asm volatile("mova 1f,%0\n\t" \
+ "add %1,%0\n\t" \
+ "jmp @r0 ! Jump to P2 area\n\t" \
+ " nop\n\t" \
+ ".balign 4\n" \
+ "1:" \
+ : "=&z" (__dummy) \
+ : "r" (0x20000000))
+
+#define back_to_p1(__dummy) \
+ asm volatile("nop;nop;nop;nop;nop;nop\n\t" \
+ "mova 9f,%0\n\t" \
+ "sub %1,%0\n\t" \
+ "jmp @r0 ! Back to P1 area\n\t" \
+ " nop\n\t" \
+ ".balign 4\n" \
+ "9:" \
+ : "=&z" (__dummy) \
+ : "r" (0x20000000), "0" (__dummy))
+
+/* Write back caches to memory (if needed) and invalidates the caches */
+void cache_flush_area(unsigned long start, unsigned long end)
+{
+ unsigned long flags, __dummy;
+ unsigned long addr, data, v, p;
+
+ start &= ~(L1_CACHE_BYTES-1);
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+
+ for (v = start; v < end; v+=L1_CACHE_BYTES) {
+ p = __pa(v);
+ addr = CACHE_IC_ADDRESS_ARRAY |
+ (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+ data = (v&0xfffffc00); /* U=0, V=0 */
+ ctrl_outl(data,addr);
+#if CACHE_IC_ADDRESS_ARRAY != CACHE_OC_ADDRESS_ARRAY
+ asm volatile("ocbp %0"
+ : /* no output */
+ : "m" (__m(v)));
+#endif
+ }
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+/* Purge (just invalidate, no write back) the caches */
+/* This is expected to work well.. but..
+
+ On SH7708S, the write-back cache is written back on "purge".
+ (it's not expected, though).
+
+ It seems that we have no way to just purge (with no write back action)
+ the cache line. */
+void cache_purge_area(unsigned long start, unsigned long end)
+{
+ unsigned long flags, __dummy;
+ unsigned long addr, data, v, p, j;
+
+ start &= ~(L1_CACHE_BYTES-1);
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+
+ for (v = start; v < end; v+=L1_CACHE_BYTES) {
+ p = __pa(v);
+ for (j=0; j<CACHE_IC_NUM_WAYS; j++) {
+ addr = CACHE_IC_ADDRESS_ARRAY|(j<<CACHE_IC_WAY_SHIFT)|
+ (v&CACHE_IC_ENTRY_MASK);
+ data = ctrl_inl(addr);
+ if ((data & 0xfffffc00) == (p&0xfffffc00)
+ && (data & CACHE_VALID)) {
+ data &= ~CACHE_VALID;
+ ctrl_outl(data,addr);
+ break;
+ }
+ }
+#if CACHE_IC_ADDRESS_ARRAY != CACHE_OC_ADDRESS_ARRAY
+ asm volatile("ocbi %0"
+ : /* no output */
+ : "m" (__m(v)));
+#endif
+ }
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+/* write back the dirty cache, but not invalidate the cache */
+void cache_wback_area(unsigned long start, unsigned long end)
+{
+ unsigned long flags, __dummy;
+ unsigned long v;
+
+ start &= ~(L1_CACHE_BYTES-1);
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+
+ for (v = start; v < end; v+=L1_CACHE_BYTES) {
+#if CACHE_IC_ADDRESS_ARRAY == CACHE_OC_ADDRESS_ARRAY
+ unsigned long addr, data, j;
+ unsigned long p = __pa(v);
+
+ for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
+ addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
+ (v&CACHE_OC_ENTRY_MASK);
+ data = ctrl_inl(addr);
+ if ((data & 0xfffffc00) == (p&0xfffffc00)
+ && (data & CACHE_VALID)
+ && (data & CACHE_UPDATED)) {
+ data &= ~CACHE_UPDATED;
+ ctrl_outl(data,addr);
+ break;
+ }
+ }
+#else
+ asm volatile("ocbwb %0"
+ : /* no output */
+ : "m" (__m(v)));
+#endif
+ }
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+/*
+ * Write back the cache.
+ *
+ * For SH-4, flush (write back) Operand Cache, as Instruction Cache
+ * doesn't have "updated" data.
+ */
+static void cache_wback_all(void)
+{
+ unsigned long flags, __dummy;
+ unsigned long addr, data, i, j;
+
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+
+ for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
+ for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
+ addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
+ (i<<CACHE_OC_ENTRY_SHIFT);
+ data = ctrl_inl(addr);
+ if (data & CACHE_VALID) {
+ data &= ~(CACHE_VALID|CACHE_UPDATED);
+ ctrl_outl(data,addr);
+ }
+ }
+ }
+
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+static void
+detect_cpu_and_cache_system(void)
+{
+#if defined(__sh3__)
+ unsigned long __dummy, addr0, addr1, data0, data1, data2, data3;
+
+ jump_to_p2(__dummy);
+ /* Check if the entry shadows or not.
+ * When shadowed, it's 128-entry system.
+ * Otherwise, it's 256-entry system.
+ */
+ addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
+ addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
+ data0 = ctrl_inl(addr0);
+ data0 ^= 0x00000001;
+ ctrl_outl(data0,addr0);
+ data1 = ctrl_inl(addr1);
+ data2 = data1 ^ 0x00000001;
+ ctrl_outl(data2,addr1);
+ data3 = ctrl_inl(addr0);
+
+ /* Invaliate them, in case the cache has been enabled already. */
+ ctrl_outl(data0&~0x00000001,addr0);
+ ctrl_outl(data2&~0x00000001,addr1);
+ back_to_p1(__dummy);
+
+ if (data0 == data1 && data2 == data3) { /* Shadow */
+ cache_system_info.way_shift = 11;
+ cache_system_info.entry_mask = 0x7f0;
+ cache_system_info.num_entries = 128;
+ cpu_data->type = CPU_SH7708;
+ } else { /* 7709A or 7729 */
+ cache_system_info.way_shift = 12;
+ cache_system_info.entry_mask = 0xff0;
+ cache_system_info.num_entries = 256;
+ cpu_data->type = CPU_SH7729;
+ }
+#elif defined(__SH4__)
+ cpu_data->type = CPU_SH7750;
+#endif
+}
+
+void __init cache_init(void)
+{
+ unsigned long __dummy, ccr;
+
+ detect_cpu_and_cache_system();
+
+ ccr = ctrl_inl(CCR);
+ if (ccr == CCR_CACHE_VAL)
+ return;
+ if (ccr & CCR_CACHE_ENABLE)
+ /* Should check RA here. If RA was 1,
+ we only need to flush the half of the caches. */
+ cache_wback_all();
+
+ jump_to_p2(__dummy);
+ ctrl_outl(CCR_CACHE_INIT, CCR);
+ back_to_p1(__dummy);
+}
+
+#if defined(__SH4__)
+/* Write back data caches, and invalidates instructiin caches */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ unsigned long flags, __dummy;
+ unsigned long addr, data, v;
+
+ start &= ~(L1_CACHE_BYTES-1);
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+
+ for (v = start; v < end; v+=L1_CACHE_BYTES) {
+ /* Write back O Cache */
+ asm volatile("ocbwb %0"
+ : /* no output */
+ : "m" (__m(v)));
+ /* Invalidate I Cache */
+ addr = CACHE_IC_ADDRESS_ARRAY |
+ (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+ data = (v&0xfffffc00); /* Valid=0 */
+ ctrl_outl(data,addr);
+ }
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+void flush_cache_all(void)
+{
+ unsigned long flags,__dummy;
+
+ /* Write back Operand Cache */
+ cache_wback_all ();
+
+ /* Then, invalidate Instruction Cache and Operand Cache */
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+ ctrl_outl(CCR_CACHE_INIT, CCR);
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+ /* Is there any good way? */
+ /* XXX: possibly call flush_cache_range for each vm area */
+ flush_cache_all();
+}
+
+void flush_cache_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ unsigned long flags, __dummy;
+ unsigned long addr, data, v;
+
+ start &= ~(L1_CACHE_BYTES-1);
+ save_and_cli(flags);
+ jump_to_p2(__dummy);
+
+ for (v = start; v < end; v+=L1_CACHE_BYTES) {
+ addr = CACHE_IC_ADDRESS_ARRAY |
+ (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+ data = (v&0xfffffc00); /* Update=0, Valid=0 */
+ ctrl_outl(data,addr);
+ addr = CACHE_OC_ADDRESS_ARRAY |
+ (v&CACHE_OC_ENTRY_MASK) | 0x8 /* A-bit */;
+ ctrl_outl(data,addr);
+ }
+ back_to_p1(__dummy);
+ restore_flags(flags);
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
+{
+ flush_cache_range(vma->vm_mm, addr, addr+PAGE_SIZE);
+}
+
+void flush_page_to_ram(unsigned long page)
+{ /* Page is in physical address */
+ /* XXX: for the time being... */
+ flush_cache_all();
+}
+#endif
-/*
+/* $Id: extable.c,v 1.1 1999/09/18 16:57:37 gniibe Exp $
+ *
* linux/arch/sh/mm/extable.c
* Taken from:
* linux/arch/i386/mm/extable.c
-/*
+/* $Id: fault.c,v 1.3 1999/09/21 23:09:53 gniibe Exp $
+ *
* linux/arch/sh/mm/fault.c
* Copyright (C) 1999 Niibe Yutaka
*
#include <linux/interrupt.h>
#include <asm/system.h>
+#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/hardirq.h>
asid = get_asid();
- save_and_cli(flags);
address &= PAGE_MASK;
+#if 0/*defined(__SH4__)*//* SH-4 has separate I/D caches: XXX really needed? */
+ if ((vma->vm_flags & VM_EXEC) != 0)
+/* &&
+ ((pte_val(pte) & (_PAGE_PRESENT | _PAGE_DIRTY)) ==
+ (_PAGE_PRESENT | _PAGE_DIRTY))) */
+ flush_icache_range(address,address+PAGE_SIZE);
+#endif
+ save_and_cli(flags);
/* Set PTEH register */
- asm volatile ("mov.l %0,%1"
- : /* no output */
- : "r" (address | asid), "m" (__m(MMU_PTEH)));
+ ctrl_outl((address|asid), MMU_PTEH);
pteval = pte_val(pte);
pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */
/* Set PTEL register */
- asm volatile ("mov.l %0,%1"
- : /* no output */
- : "r" (pteval), "m" (__m(MMU_PTEL)));
+ ctrl_outl(pteval, MMU_PTEL);
/* Load the TLB */
asm volatile ("ldtlb" : /* no output */ : /* no input */
{
unsigned long addr, data;
+#if defined(__sh3__)
addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000) | MMU_PAGE_ASSOC_BIT;
data = page | asid; /* VALID bit is off */
- __asm__ __volatile__ ("mov.l %0,%1"
- : /* no output */
- : "r" (data), "m" (__m(addr)));
+ ctrl_outl(data, addr);
+#elif defined(__SH4__)
+ int i;
+
+ addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
+ data = page | asid; /* VALID bit is off */
+ ctrl_outl(data, addr);
+
+ for (i=0; i<4; i++) {
+ addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
+ data = ctrl_inl(addr);
+ data &= ~0x30;
+ if (data == (page | asid)) {
+ ctrl_outl(data, addr);
+ break;
+ }
+ }
+#endif
}
void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
unsigned long asid;
if (vma->vm_mm->context != NO_CONTEXT) {
+ unsigned long flags;
+
page &= PAGE_MASK;
asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
+ save_and_cli(flags);
__flush_tlb_page (asid, page);
+ restore_flags(flags);
}
}
save_and_cli(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
- if (size > (MMU_NTLB_ENTRIES/4)) { /* So many TLB to flush */
+ if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
get_new_mmu_context(mm);
if (mm == current->mm)
set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
void flush_tlb_all(void)
{
- unsigned long flags, __dummy;
+ unsigned long flags, status;
save_and_cli(flags);
- asm volatile("mov.l %1,%0\n\t"
- "or #4,%0\n\t" /* Set TF-bit to flush */
- "mov.l %0,%1"
- : "=&z" (__dummy)
- : "m" (__m(MMUCR)));
+ status = ctrl_inl(MMUCR);
+ status |= 0x04; /* Set TF-bit to flush */
+ ctrl_outl(status,MMUCR);
restore_flags(flags);
}
-/*
+/* $Id: init.c,v 1.3 1999/10/11 10:41:30 gniibe Exp $
+ *
* linux/arch/sh/mm/init.c
*
* Copyright (C) 1999 Niibe Yutaka
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
+#include <asm/io.h>
/*
* Cache of MMU context last used.
*/
pte_t * __bad_pagetable(void)
{
- extern char empty_bad_page_table[PAGE_SIZE];
+ extern unsigned long empty_bad_page_table[PAGE_SIZE];
unsigned long page = (unsigned long)empty_bad_page_table;
clear_page(page);
pgd_val(pg_dir[0]) = 0;
/* Enable MMU */
- __asm__ __volatile__ ("mov.l %0,%1"
- : /* no output */
- : "r" (MMU_CONTROL_INIT), "m" (__m(MMUCR)));
+ ctrl_outl(MMU_CONTROL_INIT, MMUCR);
+
+ mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
+ set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
return free_area_init(start_mem, end_mem);
}
unsigned long empty_bad_page[1024];
unsigned long empty_bad_page_table[1024];
-unsigned long empty_zero_page[1024];
+extern unsigned long empty_zero_page[1024];
void __init mem_init(unsigned long start_mem, unsigned long end_mem)
{
-/*
+/* $Id: ioremap.c,v 1.1 1999/09/18 16:57:48 gniibe Exp $
+ *
* arch/sh/mm/ioremap.c
*
* Re-map IO memory to kernel address space so that we can access it.
-/* ld script to make SuperH Linux kernel
+/* $Id: vmlinux.lds.S,v 1.3 1999/10/05 12:33:48 gniibe Exp $
+ * ld script to make SuperH Linux kernel
* Written by Niibe Yutaka
*/
#include <linux/config.h>
__text = .; /* Text and read-only data */
_text = .; /* Text and read-only data */
.text : {
+ *(.empty_zero_page)
*(.text)
*(.fixup)
*(.gnu.warning)
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
- . = ALIGN(4096);
- .data.disk_image : { *(.data.disk_image) }
-
. = ALIGN(4);
___bss_start = .; /* BSS */
.bss : {
fi
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
- "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
- bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+ bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA
fi
bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366
fi
if [ "$CONFIG_X86" = "y" ]; then
bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
- "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
- bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
+ if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+ bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING
fi
fi
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
fi
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
- if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
- "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
- bool ' Special UDMA Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_BURST_BIT
- bool ' Special Mode Feature (DANGEROUS)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+ if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+ bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+ fi
+ fi
+ if [ "$CONFIG_X86" = "y" ]; then
+ bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
fi
- fi
- if [ "$CONFIG_X86" = "y" ]; then
- bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
fi
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
if [ "$CONFIG_X86" = "y" ]; then
- bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
+ bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX
fi
fi
fi
bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
- if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
- "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
fi
bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
"$CONFIG_BLK_DEV_HPT366" = "y" -o \
"$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
"$CONFIG_BLK_DEV_OPTI621" = "y" -o \
+ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
"$CONFIG_BLK_DEV_PIIX" = "y" -o \
"$CONFIG_BLK_DEV_SIS5513" = "y" -o \
"$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
IDE_OBJS += umc8672.o
endif
-ifeq ($(CONFIG_BLK_DEV_VIA82C586),y)
-IDE_OBJS += via82c586.o
+ifeq ($(CONFIG_BLK_DEV_VIA82CXXX),y)
+IDE_OBJS += via82cxxx.o
endif
### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
ide-probe-mod.o: ide-probe.o ide-geometry.o
$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
-
/*
- * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998
+ * linux/drivers/block/aec6210.c Version 0.02 Sept. 3, 1999
*
- * Copyright (C) 1998-99 Andre Hedrick
+ * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
*
* pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02
* pio 1 :: 40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02
#include <asm/io.h>
#include <asm/irq.h>
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+
unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
{
if (dev->resource[PCI_ROM_RESOURCE].start) {
/*
- * linux/drivers/block/alim15x3.c Version 0.05 Jun. 29, 1999
+ * linux/drivers/block/alim15x3.c Version 0.06 Sept. 3, 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)
+ * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
*
- * Default disable (U)DMA on all devices execpt hard disks.
- * This measure of overkill is needed to stablize the chipset code.
+ * (U)DMA capable version of ali 1533/1543(C), 1535(D)
*
+ * version: 1.0 beta2 (Sep. 2, 1999)
+ * e-mail your problems to cjtsai@ali.com.tw
+ *
+ **********************************************************************
+ * 9/7/99 --Parts from the above author are included and need to be
+ * converted into standard interface, once I finish the thought.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/io.h>
"error DRQ ",
"error DRQ busy"
};
-#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
-{
- ide_pio_data_t d;
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- int s_time, a_time, c_time;
- byte s_clc, a_clc, r_clc;
- unsigned long flags;
- int bus_speed = ide_system_bus_speed();
- int port = hwif->index ? 0x5c : 0x58;
-
- pio = ide_get_best_pio_mode(drive, pio, 5, &d);
- s_time = ide_pio_timings[pio].setup_time;
- a_time = ide_pio_timings[pio].active_time;
- if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
- s_clc = 0;
- if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
- a_clc = 0;
- c_time = ide_pio_timings[pio].cycle_time;
-
-#if 0
- if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
- r_clc = 0;
-#endif
- if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
- r_clc = 1;
- } else {
- if (r_clc >= 16)
- r_clc = 0;
- }
- save_flags(flags);
- cli();
- pci_write_config_byte(dev, port, s_clc);
- pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
- restore_flags(flags);
-
- /*
- * setup active rec
- * { 70, 165, 365 }, PIO Mode 0
- * { 50, 125, 208 }, PIO Mode 1
- * { 30, 100, 110 }, PIO Mode 2
- * { 30, 80, 70 }, PIO Mode 3 with IORDY
- * { 25, 70, 25 }, PIO Mode 4 with IORDY ns
- * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
- */
-
-}
-
-unsigned int __init 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 */
-}
-
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{
- struct pci_dev *dev;
- byte ideic, inmir, iderev;
- byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6,
- 1, 11, 0, 12, 0, 14, 0, 15 };
-
- pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev);
-
- 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) */
-
- hwif->tuneproc = &ali15x3_tune_drive;
- if ((hwif->dma_base) && (iderev >= 0xC1)) {
- /* M1543C or newer for DMAing */
- hwif->dmaproc = &ali15x3_dmaproc;
- } else {
- hwif->autodma = 0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- }
- 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;
return p-buffer; /* => must be less than 4k! */
}
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static byte m5229_revision = 0;
+static byte chip_is_1543c_e = 0;
+static byte cable_80_pin[2] = { 0, 0 };
+
+byte ali_proc = 0;
+static struct pci_dev *isa_dev;
+
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
+{
+ ide_pio_data_t d;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int s_time, a_time, c_time;
+ byte s_clc, a_clc, r_clc;
+ unsigned long flags;
+ int bus_speed = ide_system_bus_speed();
+ int port = hwif->index ? 0x5c : 0x58;
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+ s_time = ide_pio_timings[pio].setup_time;
+ a_time = ide_pio_timings[pio].active_time;
+ if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+ s_clc = 0;
+ if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+ a_clc = 0;
+ c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+ if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+ r_clc = 0;
+#endif
+
+ if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+ r_clc = 1;
+ } else {
+ if (r_clc >= 16)
+ r_clc = 0;
+ }
+ save_flags(flags);
+ cli();
+ pci_write_config_byte(dev, port, s_clc);
+ pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+ restore_flags(flags);
+
+ /*
+ * setup active rec
+ * { 70, 165, 365 }, PIO Mode 0
+ * { 50, 125, 208 }, PIO Mode 1
+ * { 30, 100, 110 }, PIO Mode 2
+ * { 30, 80, 70 }, PIO Mode 3 with IORDY
+ * { 25, 70, 25 }, PIO Mode 4 with IORDY ns
+ * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
+ */
+
+}
+
+static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
+{
+ if (bits & 0x04)
+ return XFER_MW_DMA_2;
+ if (bits & 0x02)
+ return XFER_MW_DMA_1;
+ return XFER_MW_DMA_0;
+}
+
+static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
+{
+ if (bits & 0x10)
+ return XFER_UDMA_4;
+ if (bits & 0x08)
+ return XFER_UDMA_3;
+ if (bits & 0x04)
+ return XFER_UDMA_2;
+ if (bits & 0x02)
+ return XFER_UDMA_1;
+ return XFER_UDMA_0;
+}
+
+static __inline__ int wait_for_ready(ide_drive_t *drive)
+{
+ int timeout = 20000; /* (old value: 100) */
+ byte stat;
+
+ while (--timeout) {
+ stat = GET_STAT();
+ /*
+ * printk("STAT(%2x) ", stat);
+ */
+ if (!(stat & BUSY_STAT)) {
+ if ((stat & READY_STAT) || (stat & ERR_STAT)) {
+ break;
+ }
+ }
+ /*
+ * (old value: 100)
+ */
+ udelay(150);
+ }
+ if ((stat & ERR_STAT) || timeout <= 0)
+ return 1;
+ return 0;
+}
+
+static void ali15x3_do_setfeature(ide_drive_t *drive, byte command)
+{
+ unsigned long flags;
+ byte old_select;
+
+ save_flags(flags);
+ cli();
+
+ /* save old selected device */
+ old_select = IN_BYTE(IDE_SELECT_REG);
+ /* "SELECT " */
+ OUT_BYTE(drive->select.all, IDE_SELECT_REG);
+ /* "SETXFER " */
+ OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+ /* "CMND " */
+ OUT_BYTE(command, IDE_NSECTOR_REG);
+
+ if(wait_for_ready(drive)) /* "wait " */
+ goto out;
+
+ /* "SETFEATURE " */
+ OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+ /* "wait " */
+ (void) wait_for_ready(drive);
+
+out:
+ /*
+ * restore to old "selected device"
+ */
+ OUT_BYTE(old_select, IDE_SELECT_REG);
+ restore_flags(flags);
+}
+
+static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
+{
+ byte unit = (drive->select.b.unit & 0x01);
+ byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
+ byte tmpbyte;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long flags;
+ int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
+
+ ali15x3_do_setfeature(drive, dma2_bits_to_command(bits));
+
+ /*
+ * clear "ultra enable" bit
+ */
+ pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
+ if (unit) {
+ tmpbyte &= 0x7f;
+ } else {
+ tmpbyte &= 0xf7;
+ }
+ save_flags(flags);
+ cli();
+ pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
+ restore_flags(flags);
+ drive->id->dma_ultra = 0x00;
+
+ /*
+ * Enable DMA
+ */
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+ printk("ALI15X3: MultiWord DMA enabled\n");
+}
+
+static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base)
+{
+ byte unit = (drive->select.b.unit & 0x01);
+ byte bits = drive->id->dma_ultra & 0x1f;
+ byte tmpbyte;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long flags;
+ unsigned char udma_mode = 0;
+ int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
+
+ if (bits & 0x18) {
+ /*
+ * 00011000, disk: ultra66
+ */
+ if (m5229_revision < 0xc2) {
+ /*
+ * controller: ultra33
+ */
+ bits = 0x04;
+ /*
+ * 00000100, use ultra33, mode 2
+ */
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0004;
+ } else {
+ /*
+ * controller: ultra66
+ *
+ * Try to detect word93 bit13 and
+ * 80-pin cable (from host view)
+ */
+ if (!((drive->id->word93 & 0x2000) &&
+ cable_80_pin[hwif->channel])) {
+ bits = 0x04;
+ /*
+ * 00000100, use ultra33, mode 2
+ */
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0004;
+ }
+ }
+ }
+
+ /*
+ * set feature regardless
+ */
+ ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits));
+ udma_mode &= 0x0f; /* get UDMA mode */
+
+ /*
+ * Enable DMA and UltraDMA
+ */
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+ /*
+ * m5229 ultra
+ */
+ pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
+ /*
+ * clear bit0~3 or bit 4~7
+ */
+ tmpbyte &= (0x0f << ((1-unit) << 2));
+ /*
+ * enable ultra dma and set timing
+ */
+ tmpbyte |= ((0x08 | (4-udma_mode)) << (unit << 2));
+ /*
+ * set to m5229
+ */
+ save_flags(flags);
+ cli();
+ pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
+ restore_flags(flags);
+
+ if (udma_mode >= 3) {
+ /*
+ * ultra 66
+ */
+ pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte);
+ tmpbyte |= 1;
+ save_flags(flags);
+ cli();
+ pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte);
+ restore_flags(flags);
+ }
+
+ printk("ALI15X3: Ultra DMA enabled\n");
+}
+
+static int ali15x3_dma_onoff(ide_drive_t *drive, int enable)
+{
+ if (enable) {
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ struct hd_driveid *id = drive->id;
+
+ if ((id->field_valid & 0x0004) &&
+ (id->dma_ultra & 0x001f)) {
+ /*
+ * 1543C_E, in ultra mode, WDC "harddisk"
+ * will cause "CRC" errors (even if no CRC problem),
+ * so we try to use "DMA" here
+ */
+ if (m5229_revision <= 0x20) {
+ /*
+ * Normal MultiWord DMA modes.
+ */
+ ali15x3_dma2_enable(drive, dma_base);
+ } else if ((m5229_revision < 0xC2) &&
+ ((drive->media!=ide_disk) ||
+ (chip_is_1543c_e &&
+ strstr(id->model, "WDC ")))) {
+ /*
+ * Normal MultiWord DMA modes.
+ */
+ ali15x3_dma2_enable(drive, dma_base);
+ } else {
+ /*
+ * m5229_revision >= 0xC2 for UltraDMA modes.
+ */
+ ali15x3_udma_enable(drive, dma_base);
+ }
+ } else {
+ /*
+ * Normal MultiWord DMA modes.
+ */
+ ali15x3_dma2_enable(drive, dma_base);
+ }
+ }
+
+ drive->using_dma = enable; /* on, off */
+ return 0;
+}
+
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+ return hwif->dmaproc(ide_dma_off_quietly, drive);
+ /*
+ * Even if the drive is not _currently_ in a DMA
+ * mode, we succeed, and we'll enable it manually
+ * below in alim15x3_dma_onoff
+ */
+ if ((id != NULL) && (id->capability & 1) && hwif->autodma) {
+ if (id->field_valid & 0x0004) {
+ if (id->dma_ultra & 0x001F)
+ return hwif->dmaproc(ide_dma_on, drive);
+ }
+ if (id->field_valid & 0x0002) {
+ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007))
+ return hwif->dmaproc(ide_dma_on, drive);
+ }
+ }
+ return hwif->dmaproc(ide_dma_off_quietly, drive);
+}
+
+static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch(func) {
+ case ide_dma_check:
+ return ali15x3_config_drive_for_dma(drive);
+ case ide_dma_on:
+ case ide_dma_off:
+ case ide_dma_off_quietly:
+ return ali15x3_dma_onoff(drive, (func == ide_dma_on));
+ case ide_dma_write:
+ if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+ return 1; /* try PIO instead of DMA */
+ break;
+ default:
+ break;
+ }
+
+ return ide_dmaproc(func, drive); /* use standard DMA stuff */
+}
+
+unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
+{
+ struct pci_dev *isa;
+ unsigned long fixdma_base = dev->resource[4].start;
+ byte tmpbyte;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+ for (isa = pci_devices; isa; isa=isa->next) {
+ /*
+ * look for ISA bridge
+ */
+ if (isa->vendor == PCI_VENDOR_ID_AL &&
+ isa->device == PCI_DEVICE_ID_AL_M1533) {
+ isa_dev = isa;
+ break;
+ }
+ }
+
+ if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
+ /*
+ *
+ */
+ } else {
+ /*
+ * enable DMA capable bit, and "not" simplex only
+ */
+ outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
+
+ if (inb(fixdma_base+2) & 0x80)
+ printk("%s: simplex device: DMA will fail!!\n", name);
+ }
+
+ /*
+ * FIXME !!! This detection needs to be in "ata66_ali15x3()"
+ * below as a standard detection return.
+ */
+
+ if (m5229_revision >= 0xC2) {
+ unsigned long flags;
+ /*
+ * 1543C-B?, 1535, 1535D, 1553
+ * Note 1: not all "motherboard" support this detection
+ * Note 2: if no udma 66 device, the detection may "error".
+ * but in this case, we will not set the device to
+ * ultra 66, the detection result is not important
+ */
+ save_flags(flags);
+ cli();
+
+ /*
+ * enable "Cable Detection", m5229, 0x4b, bit3
+ */
+ pci_read_config_byte(dev, 0x4b, &tmpbyte);
+ pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+ /*
+ * set south-bridge's enable bit, m1533, 0x79
+ */
+ pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+ if (m5229_revision == 0xC2) {
+ /*
+ * 1543C-B0 (m1533, 0x79, bit 2)
+ */
+ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+ } else if (m5229_revision == 0xC3) {
+ /*
+ * 1553/1535 (m1533, 0x79, bit 1)
+ */
+ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+ }
+ restore_flags(flags);
+ /*
+ * Ultra66 cable detection (from Host View)
+ * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+ */
+ pci_read_config_byte(dev, 0x4a, &tmpbyte);
+ /*
+ * 0x4a, bit0 is 0 => primary channel
+ * has 80-pin (from host view)
+ */
+ if (!(tmpbyte & 0x01))
+ cable_80_pin[0] = 1;
+ /*
+ * 0x4a, bit1 is 0 => secondary channel
+ * has 80-pin (from host view)
+ */
+ if (!(tmpbyte & 0x02))
+ cable_80_pin[1] = 1;
+ } else {
+ unsigned long flags;
+ /*
+ * revision 0x20 (1543-E, 1543-F)
+ * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+ * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+ */
+ pci_read_config_byte(dev, 0x4b, &tmpbyte);
+ save_flags(flags);
+ cli();
+ /*
+ * clear bit 7
+ */
+ pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+ restore_flags(flags);
+
+ /*
+ * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+ */
+ pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+ chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+ }
+
+ return 0;
+}
+
+unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+ /*
+ * FIXME !!!!
+ * {0x4a,0x01,0x01}, {0x4a,0x02,0x02}
+ */
+ return 0;
+}
+
+void __init ide_init_ali15x3 (ide_hwif_t *hwif)
+{
+ 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;
+
+ if (isa_dev) {
+ /*
+ * read IDE interface control
+ */
+ pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+ /* bit0, bit1 */
+ ideic = ideic & 0x03;
+
+ /* get IRQ for IDE Controller */
+ if ((hwif->channel && ideic == 0x03) ||
+ (!hwif->channel && !ideic)) {
+ /*
+ * get SIRQ1 routing table
+ */
+ pci_read_config_byte(isa_dev, 0x44, &inmir);
+ inmir = inmir & 0x0f;
+ hwif->irq = irq_routing_table[inmir];
+ } else if (hwif->channel && !(ideic & 0x01)) {
+ /*
+ * get SIRQ2 routing table
+ */
+ pci_read_config_byte(isa_dev, 0x75, &inmir);
+ inmir = inmir & 0x0f;
+ hwif->irq = irq_routing_table[inmir];
+ }
+ }
+
+ hwif->tuneproc = &ali15x3_tune_drive;
+ if ((hwif->dma_base) && (m5229_revision >= 0xC1)) {
+ /*
+ * M1543C or newer for DMAing
+ */
+ hwif->dmaproc = &ali15x3_dmaproc;
+ hwif->autodma = 1;
+ } else {
+ hwif->autodma = 0;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ }
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+ ali_proc = 1;
+ bmide_dev = hwif->pci_dev;
+ ali_display_info = &ali_get_info;
+#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+ return;
+}
+
+void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+ if ((dmabase) && (m5229_revision < 0x20)) {
+ return;
+ }
+ ide_setup_dma(hwif, dmabase, 8);
+}
/*
- * linux/drivers/block/cy82c693.c Version 0.33 Jan. 23, 1999
+ * linux/drivers/block/cy82c693.c Version 0.34 Sept 3, 1999
*
- * Copyright (C) 1998, 1999 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- * Copyright (C) 1998 Andre Hedrick, Integrater
+ * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ * Copyright (C) 1998-99 Andre Hedrick, Integrater
*
* CYPRESS CY82C693 chipset IDE controller
*
*
*
* History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
* ASK@1999-01-23: v0.33 made a few minor code clean ups
* removed DMA clock speed setting by default
* added boot message
#include "ide_modes.h"
/* the current version */
-#define CY82_VERSION "CY82C693U driver v0.33 99-01-23 Andreas S. Krebs (akrebs@altavista.net)"
+#define CY82_VERSION "CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)"
/*
* The following are used to debug the driver.
unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
{
- return 0;
-}
-
-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");
data = IN_BYTE(CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "CY82U693: Peripheral Configuration Register: 0x%X\n", data);
+ printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
#endif /* CY82C693_DEBUG_INFO */
/*
OUT_BYTE(data, CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "CY82U693: New Peripheral Configuration Register: 0x%X\n", data);
+ printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
#endif /* CY82C693_DEBUG_INFO */
-#endif /* CY82C693_SETDMA_CLOCK */
+#endif /* CY82C693_SETDMA_CLOCK */
+ return 0;
}
/*
if (hwif->dma_base)
hwif->dmaproc = &cy82c693_dmaproc;
hwif->tuneproc = &cy82c693_tune_drive;
-
- init_cy82c693_chip(hwif->pci_dev);
}
/*
- * linux/drivers/block/hpt34x.c Version 0.25 July 11, 1999
+ * linux/drivers/block/hpt34x.c Version 0.27 Sept 03, 1999
+ *
+ * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
*
- * Copyright (C) 1998-99 Andre Hedrick
*
* 00:12.0 Unknown mass storage controller:
* Triones Technologies, Inc.
* 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 <linux/config.h>
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);
+ tmp2 = (reg2 & ~(0x11 << drive_number));
pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
}
* 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)
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
byte speed = 0x00;
return ((int) ide_dma_off_quietly);
#endif /* HPT343_DISABLE_ALL_DMAING */
- if (id->dma_ultra & 0x0010) {
- goto backspeed;
- } else if (id->dma_ultra & 0x0008) {
- goto backspeed;
- } else if (id->dma_ultra & 0x0004) {
-backspeed:
- if (!((id->dma_ultra >> 8) & 4)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0404;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
+ hpt34x_clear_chipset(drive);
+
+ if ((id->dma_ultra & 0x0010) && ultra) {
speed = XFER_UDMA_2;
- } else if (id->dma_ultra & 0x0002) {
- if (!((id->dma_ultra >> 8) & 2)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0202;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
+ } else if ((id->dma_ultra & 0x0008) && ultra) {
+ speed = XFER_UDMA_2;
+ } else if ((id->dma_ultra & 0x0004) && ultra) {
+ speed = XFER_UDMA_2;
+ } else if ((id->dma_ultra & 0x0002) && ultra) {
speed = XFER_UDMA_1;
- } else if (id->dma_ultra & 0x0001) {
- if (!((id->dma_ultra >> 8) & 1)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0101;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
+ } else if ((id->dma_ultra & 0x0001) && ultra) {
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);
{
byte speed;
- hpt34x_clear_chipset(drive);
switch(pio) {
case 4: speed = XFER_PIO_4;break;
case 3: speed = XFER_PIO_3;break;
case 1: speed = XFER_PIO_1;break;
default: speed = XFER_PIO_0;break;
}
+ hpt34x_clear_chipset(drive);
(void) hpt34x_tune_chipset(drive, speed);
}
if (id->field_valid & 4) {
if (id->dma_ultra & 0x0007) {
/* Force if Capable UltraDMA */
- dma_func = config_chipset_for_dma(drive);
+ dma_func = config_chipset_for_dma(drive, 1);
if ((id->field_valid & 2) &&
(dma_func != ide_dma_on))
goto 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);
+ dma_func = config_chipset_for_dma(drive, 0);
if (dma_func != ide_dma_on)
goto no_dma_set;
}
goto no_dma_set;
}
/* Consult the list of known "good" drives */
- dma_func = config_chipset_for_dma(drive);
+ dma_func = config_chipset_for_dma(drive, 0);
if (dma_func != ide_dma_on)
goto no_dma_set;
} else {
config_chipset_for_pio(drive);
}
+
+#if 0
+ if (dma_func == ide_dma_on)
+ dma_func = ide_dma_off;
+#endif
+
return HWIF(drive)->dmaproc(dma_func, drive);
}
int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ byte unit = (drive->select.b.unit & 0x01);
+ unsigned int count, reading = 0;
+ byte dma_stat;
+
switch (func) {
- case ide_dma_check:
- hpt34x_clear_chipset(drive);
- return config_drive_xfer_rate(drive);
-#if 0
case ide_dma_off:
case ide_dma_off_quietly:
+ outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+ break;
case ide_dma_on:
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+ break;
case ide_dma_check:
return config_drive_xfer_rate(drive);
case ide_dma_read:
+ reading = 1 << 3;
case ide_dma_write:
- case ide_dma_begin:
- case ide_dma_end:
- case ide_dma_test_irq:
-#endif
+ 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 */
+ reading |= 0x01;
+ outb(reading, dma_base); /* specify r/w */
+ outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */
+ drive->waiting_for_dma = 1;
+ if (drive->media != ide_disk)
+ return 0;
+ drive->timeout = WAIT_CMD;
+ ide_set_handler(drive, &ide_dma_intr); /* issue cmd to drive */
+ OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ return 0;
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
+ drive->waiting_for_dma = 0;
+ outb(inb(dma_base)&~1, dma_base); /* stop DMA */
+ dma_stat = inb(dma_base+2); /* get DMA status */
+ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
+ return (dma_stat & 7) != 4; /* verify good DMA status */
default:
break;
}
unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
{
+ int i = 0;
+ unsigned long hpt34xIoBase = dev->resource[4].start;
unsigned short cmd;
+ unsigned long flags;
+
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
if (cmd & PCI_COMMAND_MEMORY) {
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
}
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
} else {
- int i = 0;
- unsigned long hpt34xIoBase = dev->resource[4].start;
-
- pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
- dev->resource[0].start = (hpt34xIoBase + 0x20);
- dev->resource[1].start = (hpt34xIoBase + 0x34);
- dev->resource[2].start = (hpt34xIoBase + 0x28);
- dev->resource[3].start = (hpt34xIoBase + 0x3c);
- for(i=0; i<4; i++)
- dev->resource[i].flags |= 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->resource[0].start);
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-
- pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
}
+
+ pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+ dev->resource[0].start = (hpt34xIoBase + 0x20);
+ dev->resource[1].start = (hpt34xIoBase + 0x34);
+ dev->resource[2].start = (hpt34xIoBase + 0x28);
+ dev->resource[3].start = (hpt34xIoBase + 0x3c);
+ for(i=0; i<4; i++)
+ dev->resource[i].flags |= 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->resource[0].start);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
+
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ __restore_flags(flags); /* local CPU only */
+
return dev->irq;
}
/*
- * linux/drivers/block/hpt366.c Version 0.12 August 16, 1999
+ * linux/drivers/block/hpt366.c Version 0.13 Sept. 3, 1999
*
* Copyright (C) 1999 Andre Hedrick <andre@suse.com>
+ * May be copied or modified under the terms of the GNU General Public License
*
- * drive_number
- * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
*/
#include <linux/types.h>
};
#define HPT366_DEBUG_DRIVE_INFO 0
-#define HPT366_ALLOW_ATA66_4 0
+#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
-#define HPT366_ALLOW_ATA33_2 1
-#define HPT366_ALLOW_ATA33_1 1
-#define HPT366_ALLOW_ATA33_0 1
extern char *ide_xfer_verbose (byte xfer_rate);
+byte hpt363_shared_irq = 0;
static int check_in_drive_lists (ide_drive_t *drive, const char **list)
{
struct hd_driveid *id = drive->id;
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("check_in_drive_lists(%s, %p)\n", drive->name, list);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
while (*list) {
if (!strcmp(*list++,id->model)) {
static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
{
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("pci_bus_clock_list(speed=0x%02x, table=%p)\n", speed, chipset_table);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
for ( ; chipset_table->xfer_speed ; chipset_table++)
- if (chipset_table->xfer_speed == speed)
+ if (chipset_table->xfer_speed == speed) {
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("pci_bus_clock_list: found match: 0x%08x\n", chipset_table->chipset_settings);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
return chipset_table->chipset_settings;
+ }
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("pci_bus_clock_list: using default: 0x%08x\n", 0x01208585);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
return 0x01208585;
}
static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
{
int err;
- byte busclock;
-
#if HPT366_DEBUG_DRIVE_INFO
int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
#endif /* HPT366_DEBUG_DRIVE_INFO */
- byte regtime = (drive->select.b.unit & 0x01) ? 0x43 : 0x40;
+ byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
unsigned int reg1 = 0;
unsigned int reg2 = 0;
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("hpt366_tune_chipset(%s, speed=0x%02x)\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+
pci_read_config_dword(HWIF(drive)->pci_dev, regtime, ®1);
- pci_read_config_byte(HWIF(drive)->pci_dev, regtime|0x01, &busclock);
- switch(busclock) {
- case 0xd9:
+ /* detect bus speed by looking at control reg timing: */
+ switch((reg1 >> 8) & 7) {
+ case 5:
reg2 = pci_bus_clock_list(speed, forty_base);
break;
- case 0x85:
+ case 9:
reg2 = pci_bus_clock_list(speed, twenty_five_base);
break;
- case 0xa7:
default:
+ printk("hpt366: assuming 33Mhz PCI bus\n");
+ case 7:
reg2 = pci_bus_clock_list(speed, thirty_three_base);
break;
}
-
- if (drive->id->dword_io & 1)
- reg2 |= 0x80000000;
- else
- reg2 &= ~0x80000000;
+ /*
+ * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
+ */
+ reg2 &= ~0x80000000;
pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
err = ide_config_drive_speed(drive, speed);
#if HPT366_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d (0x%08x 0x%08x) 0x%04x\n",
- drive->name, ide_xfer_verbose(speed),
+ printk("%s: speed=0x%02x(%s), drive%d, old=0x%08x, new=0x%08x, err=0x%04x\n",
+ drive->name, speed, ide_xfer_verbose(speed),
drive_number, reg1, reg2, err);
#endif /* HPT366_DEBUG_DRIVE_INFO */
return(err);
{
struct hd_driveid *id = drive->id;
byte speed = 0x00;
+ unsigned int reg40 = 0;
+ int rval;
if ((id->dma_ultra & 0x0010) &&
(!check_in_drive_lists(drive, bad_ata66_4)) &&
(HPT366_ALLOW_ATA66_4) &&
(HWIF(drive)->udma_four)) {
- 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 = XFER_UDMA_4;
} else if ((id->dma_ultra & 0x0008) &&
(!check_in_drive_lists(drive, bad_ata66_3)) &&
(HPT366_ALLOW_ATA66_3) &&
(HWIF(drive)->udma_four)) {
- 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 = XFER_UDMA_3;
- } else if ((id->dma_ultra & 0x0004) &&
- (HPT366_ALLOW_ATA33_2) &&
- (!check_in_drive_lists(drive, bad_ata33))) {
- if (!((id->dma_ultra >> 8) & 4)) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) &&
- (HPT366_ALLOW_ATA33_1) &&
- (!check_in_drive_lists(drive, bad_ata33))) {
- if (!((id->dma_ultra >> 8) & 2)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0202;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
+ } else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
+ if (id->dma_ultra & 0x0004) {
+ speed = XFER_UDMA_2;
+ } else if (id->dma_ultra & 0x0002) {
+ speed = XFER_UDMA_1;
+ } else if (id->dma_ultra & 0x0001) {
+ speed = XFER_UDMA_0;
}
- speed = XFER_UDMA_1;
- } else if ((id->dma_ultra & 0x0001) &&
- (HPT366_ALLOW_ATA33_0) &&
- (!check_in_drive_lists(drive, bad_ata33))) {
- if (!((id->dma_ultra >> 8) & 1)) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) {
- drive->id->dma_ultra &= ~0xFF00;
- 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) {
- drive->id->dma_ultra &= ~0xFF00;
- 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 {
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_dma: returning 'ide_dma_off_quietly'\n", drive->name);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
return ((int) ide_dma_off_quietly);
}
+ /* Disable the "fast interrupt" prediction.
+ * Instead, always wait for the real interrupt from the drive!
+ */
+ {
+ byte reg51h = 0;
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h);
+ if (reg51h & 0x80)
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
+ }
+
+ /*
+ * Preserve existing PIO settings:
+ */
+ pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, ®40);
+ speed = (speed & ~0xc0000000) | (reg40 & 0xc0000000);
+
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_dma: speed=0x%04x\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
(void) hpt366_tune_chipset(drive, speed);
- return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ rval = (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);
+
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_dma: returning %d (%s)\n", drive->name, rval, rval == ide_dma_on ? "dma_on" : "dma_off");
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+ return rval;
}
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;
+ unsigned int reg40 = 0;
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_pio\n", drive->name);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
if (xfer_pio> 4)
speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
break;
}
+ /*
+ * Preserve existing DMA settings:
+ */
+ pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, ®40);
+ speed = (speed & ~0x30070000) | (reg40 & 0x30070000);
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
(void) hpt366_tune_chipset(drive, speed);
}
int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
+#if 0
byte reg50h = 0, reg52h = 0;
-
+#endif
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
{
- byte ata66 = 0;
+ byte test = 0;
- pci_read_config_byte(dev, 0x5a, &ata66);
if (dev->resource[PCI_ROM_RESOURCE].start)
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn));
+
+ pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+ if (test != 0x08)
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+ if (test != 0x78)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+ pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+ if (test != 0x08)
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+ pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+ if (test != 0x08)
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
return dev->irq;
}
+unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
+{
+ byte ata66 = 0;
+
+ pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+#ifdef DEBUG
+ printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+ ata66, (ata66 & 0x02) ? "33" : "66",
+ PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+ return ((ata66 & 0x02) ? 0 : 1);
+}
+
void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
+#if 0
+ if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) {
+ hwif->mate = &ide_hwifs[hwif->index-1];
+ hwif->mate->mate = hwif;
+ hwif->serialized = hwif->mate->serialized = 1;
+ }
+#endif
+
hwif->tuneproc = &hpt366_tune_drive;
if (hwif->dma_base) {
- byte ata66 = 0;
-
hwif->dmaproc = &hpt366_dmaproc;
- pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
- hwif->udma_four = (ata66 & 0x02) ? 0 : 1;
} else {
- hwif->udma_four = 0;
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
}
+
+void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+ byte masterdma = 0, slavedma = 0;
+ byte dma_new = 0, dma_old = inb(dmabase+2);
+ unsigned long flags;
+
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+
+ dma_new = dma_old;
+ pci_read_config_byte(hwif->pci_dev, 0x43, &masterdma);
+ pci_read_config_byte(hwif->pci_dev, 0x47, &slavedma);
+
+ if (masterdma & 0x30) dma_new |= 0x20;
+ if (slavedma & 0x30) dma_new |= 0x40;
+ if (dma_new != dma_old) outb(dma_new, dmabase+2);
+
+ __restore_flags(flags); /* local CPU only */
+
+ ide_setup_dma(hwif, dmabase, 8);
+}
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+ drive->timeout = WAIT_CMD;
+ ide_set_handler(drive, &ide_dma_intr);
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
IDE_COMMAND_REG);
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
- ide_set_handler (drive, handler, WAIT_CMD);
+ ide_set_handler (drive, handler);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
HANDLER is the interrupt handler to call when the command completes
or there's data ready. */
static int cdrom_transfer_packet_command (ide_drive_t *drive,
- char *cmd_buf, int cmd_len,
+ unsigned char *cmd_buf, int cmd_len,
ide_handler_t *handler)
{
+ /* set timeout to an hour */
+ if (cmd_buf[0] == GPCMD_BLANK || cmd_buf[0] == GPCMD_FORMAT_UNIT)
+ drive->timeout = 3600*HZ;
+
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
/* Here we should have been called after receiving an interrupt
from the device. DRQ should how be set. */
}
/* Arm the interrupt handler. */
- ide_set_handler (drive, handler, WAIT_CMD);
+ ide_set_handler (drive, handler);
/* Send the command to the device. */
atapi_output_bytes (drive, cmd_buf, cmd_len);
atapi_output_bytes (drive, &dum, sizeof (dum));
len -= sizeof (dum);
}
+ } else if (ireason == 1) {
+ /* Some drives (ASUS) seem to tell us that status
+ * info is available. just get it and ignore.
+ */
+ GET_STAT();
+ return 0;
} else {
/* Drive wants a command packet, or invalid ireason... */
printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
return -1;
}
-
/*
* Interrupt routine. Called when a read request has completed.
*/
/* Done moving data!
Wait for another interrupt. */
- ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD);
+ ide_set_handler (drive, &cdrom_read_intr);
}
return 0;
}
-
-
/*
* Routine to send a read packet command to the drive.
* This is usually called directly from cdrom_start_read.
pc.c[0] = GPCMD_READ_10;
pc.c[7] = (nframes >> 8);
pc.c[8] = (nframes & 0xff);
- put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
/* Send the command to the drive and return. */
(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
memset (&pc.c, 0, sizeof (pc.c));
pc.c[0] = GPCMD_SEEK;
- put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
}
}
-
-
/****************************************************************************
* Execute all other packet commands.
*/
struct request *rq = HWGROUP(drive)->rq;
struct packet_command *pc = (struct packet_command *)rq->buffer;
+ /* restore timeout after blank or format command */
+ drive->timeout = WAIT_CMD;
+
/* Check for errors. */
if (cdrom_decode_status (drive, 0, &stat))
return;
}
/* Now we wait for another interrupt. */
- ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD);
+ ide_set_handler (drive, &cdrom_pc_intr);
}
if (pc->sense_data == NULL)
pc->sense_data = &my_reqbuf;
pc->sense_data->sense_key = 0;
+
/* Start of retry loop. */
do {
ide_init_drive_cmd (&req);
/* End of retry loop. */
} while (pc->stat != 0 && retries >= 0);
-
/* Return an error if the command failed. */
if (pc->stat != 0)
return -EIO;
static
void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
{
- if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
- cdrom_do_packet_command (drive);
- else if (rq -> cmd == RESET_DRIVE_COMMAND) {
- cdrom_end_request (1, drive);
- ide_do_reset (drive);
- return;
- } else if (rq -> cmd != READ) {
- printk ("ide-cd: bad cmd %d\n", rq -> cmd);
- cdrom_end_request (0, drive);
- } else {
+ switch (rq->cmd) {
+ case READ: {
struct cdrom_info *info = drive->driver_data;
if (CDROM_CONFIG_FLAGS(drive)->seeking) {
if ((stat & SEEK_STAT) != SEEK_STAT) {
if (elpased < IDECD_SEEK_TIMEOUT) {
- ide_stall_queue (drive, IDECD_SEEK_TIMER);
+ ide_stall_queue(drive, IDECD_SEEK_TIMER);
return;
}
printk ("%s: DSC timeout\n", drive->name);
else
cdrom_start_read (drive, block);
info->last_block = block;
+ break;
+ }
+
+ case PACKET_COMMAND:
+ case REQUEST_SENSE_COMMAND: {
+ cdrom_do_packet_command(drive);
+ break;
+ }
+
+ case RESET_DRIVE_COMMAND: {
+ cdrom_end_request(1, drive);
+ ide_do_reset(drive);
+ break;
+ }
+
+ default: {
+ printk("ide-cd: bad cmd %d\n", rq -> cmd);
+ cdrom_end_request(0, drive);
+ break;
+ }
}
}
stat = cdrom_queue_packet_command (drive, &pc);
if (stat == 0)
- *capacity = ntohl (capbuf.lba);
+ *capacity = be32_to_cpu(capbuf.lba);
return stat;
}
-/* This gets the mechanism status per ATAPI draft spec 2.6 */
-static int
-cdrom_read_mech_status (ide_drive_t *drive, char *buf, int buflen,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.buffer = buf;
- pc.buflen = buflen;
- pc.c[0] = GPCMD_MECHANISM_STATUS;
- pc.c[8] = (buflen >> 8);
- pc.c[9] = (buflen & 0xff);
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-/* Read the drive mechanism status and slot table into our internal buffer.
- If the buffer does not yet exist, allocate it. */
-static int
-cdrom_read_changer_info (ide_drive_t *drive)
-{
- int nslots;
- struct cdrom_info *info = drive->driver_data;
-
- if (info->changer_info)
- nslots = info->changer_info->hdr.nslots;
-
- else {
- struct atapi_mechstat_header mechbuf;
- int stat;
-
- stat = cdrom_read_mech_status (drive,
- (char *)&mechbuf,
- sizeof (mechbuf),
- NULL);
- if (stat)
- return stat;
-
- nslots = mechbuf.nslots;
- info->changer_info =
- (struct atapi_changer_info *)
- kmalloc (sizeof (struct atapi_changer_info) +
- nslots * sizeof (struct atapi_slot),
- GFP_KERNEL);
- if (info->changer_info == NULL)
- return -ENOMEM;
- }
-
- return cdrom_read_mech_status
- (drive,
- (char *)&info->changer_info->hdr,
- sizeof (struct atapi_mechstat_header) +
- nslots * sizeof (struct atapi_slot),
- NULL);
-}
/* the generic packet interface to cdrom.c */
static int ide_cdrom_packet(struct cdrom_device_info *cdi,
memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
pc.buffer = cgc->buffer;
pc.buflen = cgc->buflen;
- cgc->stat = cdrom_queue_packet_command(drive, &pc);
- return cgc->stat;
+ return cgc->stat = cdrom_queue_packet_command(drive, &pc);
}
static
int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
{
ide_drive_t *drive = (ide_drive_t*) cdi->handle;
- struct cdrom_info *info = drive->driver_data;
if (slot_nr == CDSL_CURRENT) {
}
return CDS_DRIVE_NOT_READY;
- }
-
-#if ! STANDARD_ATAPI
- else if (cdi->sanyo_slot > 0)
- return CDS_NO_INFO;
-#endif /* not STANDARD_ATAPI */
-
- else {
- struct atapi_changer_info *ci;
- int stat = cdrom_read_changer_info (drive);
- if (stat < 0)
- return stat;
- ci = info->changer_info;
-
- if (ci->slots[slot_nr].disc_present)
- return CDS_DISC_OK;
- else
- return CDS_NO_DISC;
+ } else {
+ return -EINVAL;
}
}
int slot_nr)
{
ide_drive_t *drive = (ide_drive_t*) cdi->handle;
- struct cdrom_info *info = drive->driver_data;
- struct atapi_request_sense reqbuf;
- int retval;
if (slot_nr == CDSL_CURRENT) {
(void) cdrom_check_status (drive, NULL);
- retval = CDROM_STATE_FLAGS (drive)->media_changed;
CDROM_STATE_FLAGS (drive)->media_changed = 0;
+ return CDROM_STATE_FLAGS (drive)->media_changed;
+ } else {
+ return -EINVAL;
}
-
-#if ! STANDARD_ATAPI
- else if (cdi->sanyo_slot > 0) {
- retval = 0;
- }
-#endif /* not STANDARD_ATAPI */
-
- else {
- struct atapi_changer_info *ci;
- int stat = cdrom_read_changer_info (drive);
- if (stat < 0)
- return stat;
- ci = info->changer_info;
-
- /* This test may be redundant with cdrom.c. */
- if (slot_nr < 0 || slot_nr >= ci->hdr.nslots)
- return -EINVAL;
-
- retval = ci->slots[slot_nr].change;
- }
-
- /* if the media has changed, check if a disc is in the drive
- and read the toc info. */
- if (retval || !CDROM_STATE_FLAGS (drive)->toc_valid) {
- /* if cdrom_read_toc fails, return 1 to indicate
- that a disc change has occured. there might not
- be a disc in the drive. */
- if ((retval = cdrom_read_toc (drive, &reqbuf)))
- return 1;
- }
-
- return retval;
}
* be queued with ide_cdrom_packet(), which extracts the
* drive from cdi->handle. Since this device hasn't been
* registered with the Uniform layer yet, it can't do this.
- * Same goes cdi->ops.
+ * Same goes for cdi->ops.
*/
cdi->handle = (ide_drive_t *) drive;
cdi->ops = &ide_cdrom_dops;
- do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ do {
if (attempts-- <= 0)
return 0;
stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
#endif /* not STANDARD_ATAPI */
if (buf.cap.mechtype == mechtype_individual_changer ||
buf.cap.mechtype == mechtype_cartridge_changer) {
- struct atapi_mechstat_header mechbuf;
-
- stat = cdrom_read_mech_status (drive, (char*)&mechbuf,
- sizeof (mechbuf), NULL);
- if (!stat) {
+ if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
- nslots = mechbuf.nslots;
}
}
else
printk (" drive");
- printk (", %dkB Cache", ntohs(buf.cap.buffer_size));
+ printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
if (drive->using_dma) {
if ((drive->id->field_valid & 4) &&
int minor = drive->select.b.unit << PARTN_BITS;
int nslots;
- kdev_t dev = MKDEV(HWIF(drive)->major, minor);
-
- set_device_ro (dev, 1);
+ set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
blksize_size[HWIF(drive)->major][minor] = CD_FRAMESIZE;
- drive->special.all = 0;
- drive->ready_stat = 0;
+ drive->special.all = 0;
+ drive->ready_stat = 0;
+ drive->timeout = WAIT_CMD;
CDROM_STATE_FLAGS (drive)->media_changed = 1;
CDROM_STATE_FLAGS (drive)->toc_valid = 0;
info->sector_buffered = 0;
info->nsectors_buffered = 0;
info->changer_info = NULL;
+ info->last_block = 0;
+ info->start_seek = 0;
nslots = ide_cdrom_probe_capabilities (drive);
if (ide_unregister_subdriver (drive))
return 1;
if (info->sector_buffer != NULL)
- kfree (info->sector_buffer);
+ kfree(info->sector_buffer);
if (info->toc != NULL)
- kfree (info->toc);
+ kfree(info->toc);
if (info->changer_info != NULL)
- kfree (info->changer_info);
+ kfree(info->changer_info);
if (devinfo->handle == drive && unregister_cdrom (devinfo))
printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
- kfree (info);
+ kfree(info);
drive->driver_data = NULL;
return 0;
}
__u8 media_changed : 1; /* Driver has noticed a media change. */
__u8 toc_valid : 1; /* Saved TOC information is current. */
__u8 door_locked : 1; /* We think that the drive door is locked. */
- __u8 reserved : 5;
+ __u8 writing : 1; /* the drive is currently writing */
+ __u8 reserved : 4;
byte current_speed; /* Current speed of the drive */
};
#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
if (i > 0) {
if (msect)
goto read_next;
- ide_set_handler (drive, &read_intr, WAIT_CMD);
+ ide_set_handler (drive, &read_intr);
}
}
ide_end_request(1, hwgroup);
if (i > 0) {
idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
- ide_set_handler (drive, &write_intr, WAIT_CMD);
+ ide_set_handler (drive, &write_intr);
}
goto out;
}
if (stat & DRQ_STAT) {
if (rq->nr_sectors) {
ide_multwrite(drive, drive->mult_count);
- ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
+ ide_set_handler (drive, &multwrite_intr);
goto out;
}
} else {
if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
return;
#endif /* CONFIG_BLK_DEV_IDEDMA */
- ide_set_handler(drive, &read_intr, WAIT_CMD);
+ ide_set_handler(drive, &read_intr);
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
return;
}
__cli(); /* local CPU only */
if (drive->mult_count) {
HWGROUP(drive)->wrq = *rq; /* scratchpad */
- ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
+ ide_set_handler (drive, &multwrite_intr);
ide_multwrite(drive, drive->mult_count);
} else {
- ide_set_handler (drive, &write_intr, WAIT_CMD);
+ ide_set_handler (drive, &write_intr);
idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
}
return;
drive->special.all = 0;
drive->special.b.set_geometry = 1;
drive->special.b.recalibrate = 1;
+ drive->timeout = WAIT_CMD;
if (OK_TO_RESET_CONTROLLER)
drive->mult_count = 0;
if (!drive->keep_settings)
drive->waiting_for_dma = 1;
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */
+ drive->timeout = WAIT_CMD;
+ ide_set_handler(drive, &ide_dma_intr);/* issue cmd to drive */
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
case ide_dma_begin:
/* Note that this is done *after* the cmd has
switch(dev->device) {
case PCI_DEVICE_ID_CMD_643:
-#ifdef CONFIG_BLK_DEV_ALI15X3
case PCI_DEVICE_ID_AL_M5219:
- case PCI_DEVICE_ID_AL_M5229:
- /*
- * Ali 15x3 chipsets know as ALI IV and V report
- * this as simplex, skip this test for them.
- */
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
outb(inb(dma_base+2) & 0x60, dma_base+2);
if (inb(dma_base+2) & 0x80) {
printk("%s: simplex device: DMA forced\n", name);
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
idefloppy_discard_data (drive,bcount.all);
- ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);
+ ide_set_handler (drive,&idefloppy_pc_intr);
return;
}
#if IDEFLOPPY_DEBUG_LOG
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
- ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); /* And set the interrupt handler again */
+ ide_set_handler (drive,&idefloppy_pc_intr); /* And set the interrupt handler again */
}
static void idefloppy_transfer_pc (ide_drive_t *drive)
ide_do_reset (drive);
return;
}
- ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD); /* Set the interrupt routine */
+ ide_set_handler (drive, &idefloppy_pc_intr); /* Set the interrupt routine */
atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
- ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD);
+ ide_set_handler (drive, &idefloppy_transfer_pc);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
*((unsigned short *) &gcw) = drive->id->config;
drive->driver_data = floppy;
drive->ready_stat = 0;
+ drive->timeout = IDEFLOPPY_WAIT_CMD;
memset (floppy, 0, sizeof (idefloppy_floppy_t));
floppy->drive = drive;
floppy->pc = floppy->pc_stack;
#include <asm/io.h>
+extern ide_drive_t * get_info_ptr(kdev_t);
+extern unsigned long current_capacity (ide_drive_t *);
+
/*
* We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
* controller that is BIOS compatible with ST-506, and thus showing up in our
#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 DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, 0x7409})
-#define IDE_IGNORE ((void *)-1)
+#define IDE_IGNORE ((void *)-1)
#ifdef CONFIG_BLK_DEV_TRM290
extern void ide_init_trm290(ide_hwif_t *);
#define INIT_RZ1000 IDE_IGNORE
#endif
-#ifdef CONFIG_BLK_DEV_VIA82C586
-extern unsigned int pci_init_via82c568(struct pci_dev *, const char *);
-extern void ide_init_via82c586(ide_hwif_t *);
-extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase);
-#define PCI_VIA82C586 &pci_init_via82c568
-#define INIT_VIA82C586 &ide_init_via82c586
-#define DMA_VIA82C586 &ide_dmacapable_via82c586
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
+extern unsigned int ata66_via82cxxx(ide_hwif_t *);
+extern void ide_init_via82cxxx(ide_hwif_t *);
+extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+#define PCI_VIA82CXXX &pci_init_via82cxxx
+#define ATA66_VIA82CXXX &ata66_via82cxxx
+#define INIT_VIA82CXXX &ide_init_via82cxxx
+#define DMA_VIA82CXXX &ide_dmacapable_via82cxxx
#else
-#define PCI_VIA82C586 NULL
-#define INIT_VIA82C586 NULL
-#define DMA_VIA82C586 NULL
+#define PCI_VIA82CXXX NULL
+#define ATA66_VIA82CXXX NULL
+#define INIT_VIA82CXXX NULL
+#define DMA_VIA82CXXX NULL
#endif
#ifdef CONFIG_BLK_DEV_ALI15X3
extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
+extern unsigned int ata66_ali15x3(ide_hwif_t *);
extern void ide_init_ali15x3(ide_hwif_t *);
+extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
#define PCI_ALI15X3 &pci_init_ali15x3
-#define INIT_ALI15X3 &ide_init_ali15x3
+#define ATA66_ALI15X3 &ata66_ali15x3
+#define INIT_ALI15X3 &ide_init_ali15x3
+#define DMA_ALI15X3 &ide_dmacapable_ali15x3
#else
#define PCI_ALI15X3 NULL
-#define INIT_ALI15X3 NULL
+#define ATA66_ALI15X3 NULL
+#define INIT_ALI15X3 NULL
+#define DMA_ALI15X3 NULL
#endif
#ifdef CONFIG_BLK_DEV_CY82C693
extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
extern void ide_init_cy82c693(ide_hwif_t *);
#define PCI_CY82C693 &pci_init_cy82c693
-#define INIT_CY82C693 &ide_init_cy82c693
+#define INIT_CY82C693 &ide_init_cy82c693
#else
#define PCI_CY82C693 NULL
-#define INIT_CY82C693 NULL
+#define INIT_CY82C693 NULL
#endif
#ifdef CONFIG_BLK_DEV_PDC202XX
extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
+extern unsigned int ata66_pdc202xx(ide_hwif_t *);
extern void ide_init_pdc202xx(ide_hwif_t *);
#define PCI_PDC202XX &pci_init_pdc202xx
-#define INIT_PDC202XX &ide_init_pdc202xx
+#define ATA66_PDC202XX &ata66_pdc202xx
+#define INIT_PDC202XX &ide_init_pdc202xx
#else
#define PCI_PDC202XX NULL
-#define INIT_PDC202XX NULL
+#define ATA66_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
+#define INIT_PIIX &ide_init_piix
#else
-#define INIT_PIIX NULL
+#define INIT_PIIX NULL
#endif
#ifdef CONFIG_BLK_DEV_AEC6210
extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
extern void ide_init_hpt34x(ide_hwif_t *);
#define PCI_HPT34X &pci_init_hpt34x
-#define INIT_HPT34X &ide_init_hpt34x
+#define INIT_HPT34X &ide_init_hpt34x
#else
#define PCI_HPT34X NULL
-#define INIT_HPT34X NULL
+#define INIT_HPT34X NULL
#endif
#ifdef CONFIG_BLK_DEV_HPT366
+extern byte hpt363_shared_irq;
extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
+extern unsigned int ata66_hpt366(ide_hwif_t *);
extern void ide_init_hpt366(ide_hwif_t *);
+extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
#define PCI_HPT366 &pci_init_hpt366
+#define ATA66_HPT366 &ata66_hpt366
#define INIT_HPT366 &ide_init_hpt366
+#define DMA_HPT366 &ide_dmacapable_hpt366
#else
+static byte hpt363_shared_irq = 0;
#define PCI_HPT366 NULL
-#define INIT_HPT366 IDE_IGNORE
+#define ATA66_HPT366 NULL
+#define INIT_HPT366 NULL
+#define DMA_HPT366 NULL
#endif
#ifdef CONFIG_BLK_DEV_SIS5513
extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
+extern unsigned int ata66_sis5513(ide_hwif_t *);
extern void ide_init_sis5513(ide_hwif_t *);
#define PCI_SIS5513 &pci_init_sis5513
+#define ATA66_SIS5513 &ata66_sis5513
#define INIT_SIS5513 &ide_init_sis5513
#else
#define PCI_SIS5513 NULL
+#define ATA66_SIS5513 NULL
#define INIT_SIS5513 NULL
#endif
ide_pci_devid_t devid;
const char *name;
unsigned int (*init_chipset)(struct pci_dev *dev, const char *name);
+ unsigned int (*ata66_check)(ide_hwif_t *hwif);
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;
- byte sixtysix;
unsigned int extra;
} ide_pci_device_t;
static ide_pci_device_t ide_pci_chipsets[] __initdata = {
- {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
- {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
- {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
- {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
- {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_VP_IDE, "VP_IDE", PCI_VIA82C586, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, 0 },
- {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 0, 16 },
- {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 1, 48 },
- {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 },
- {DEVID_SIS5513, "SIS5513", PCI_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 1, 0 },
- {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, 0 },
- {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, 0 },
- {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 },
- {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, 16 },
- {DEVID_HPT366, "HPT366", PCI_HPT366, INIT_HPT366, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 1, 256 },
- {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0, 0 },
- {DEVID_CY82C693,"CY82C693", PCI_CY82C693, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
- {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }};
-
-static byte hpt363_shared_irq = 0;
+ {DEVID_PIIXa, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_PIIXb, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_PIIX3, "PIIX3", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_PIIX4, "PIIX4", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 },
+ {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 },
+ {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 },
+ {DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_CMD640, "CMD640", NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 },
+ {DEVID_SIS5513, "SIS5513", PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 },
+ {DEVID_CMD643, "CMD643", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_CMD646, "CMD646", NULL, NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 },
+ {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 },
+ {DEVID_TRM290, "TRM290", NULL, NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_NS87415, "NS87415", NULL, NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 },
+ {DEVID_W82C105, "W82C105", NULL, NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 },
+ {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_HPT34X, "HPT34X", PCI_HPT34X, NULL, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 },
+ {DEVID_HPT366, "HPT366", PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 256 },
+ {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_CX5530, "CX5530", NULL, NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_AMD7409, "AMD7409", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }};
/*
* This allows offboard ide-pci cards the enable a BIOS, verify interrupt
switch(dev->device) {
case PCI_DEVICE_ID_TTI_HPT343:
{
+ int i;
+ unsigned long hpt34xIoBase = dev->resource[4].start;
unsigned short pcicmd = 0;
pci_write_config_byte(dev, 0x80, 0x00);
pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
if (!(pcicmd & PCI_COMMAND_MEMORY)) {
- int i;
- unsigned long hpt34xIoBase = dev->resource[4].start;
-
- dev->resource[0].start = (hpt34xIoBase + 0x20);
- dev->resource[1].start = (hpt34xIoBase + 0x34);
- dev->resource[2].start = (hpt34xIoBase + 0x28);
- dev->resource[3].start = (hpt34xIoBase + 0x3c);
- for(i=0; i<4; i++)
- dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
} else {
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
}
+
+ dev->resource[0].start = (hpt34xIoBase + 0x20);
+ dev->resource[1].start = (hpt34xIoBase + 0x34);
+ dev->resource[2].start = (hpt34xIoBase + 0x28);
+ dev->resource[3].start = (hpt34xIoBase + 0x3c);
+ for(i=0; i<4; i++)
+ dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
}
case PCI_DEVICE_ID_TTI_HPT366:
case PCI_DEVICE_ID_PROMISE_20246:
hwif->irq = hwif->channel ? 15 : 14;
goto bypass_umc_dma;
}
- if ((!d->sixtysix) && (hwif->udma_four))
- hwif->udma_four = 0;
+ hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
#ifdef CONFIG_BLK_DEV_IDEDMA
if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X))
static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *dev2;
+ struct pci_dev *dev2 = NULL, *findev;
ide_pci_device_t *d2;
unsigned char pin1 = 0, pin2 = 0;
- d2 = d;
if (PCI_FUNC(dev->devfn) & 1)
return;
-
- for (dev2=pci_devices; dev2; dev2=dev2->next) {
- if ((dev2->vendor == dev->vendor) &&
- (dev2->device == dev->device) &&
- (PCI_FUNC(dev2->devfn) & 1))
- break;
- }
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- if (dev2) {
- pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
- hpt363_shared_irq = (pin1 != pin2) ? 1 : 0;
- }
-
- if (hpt363_shared_irq) {
- printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
- d->name, pin1, pin2);
+ for (findev=pci_devices; findev; findev=findev->next) {
+ if ((findev->vendor == dev->vendor) &&
+ (findev->device == dev->device) &&
+ ((findev->devfn - dev->devfn) == 1) &&
+ (PCI_FUNC(findev->devfn) & 1)) {
+ dev2 = findev;
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+ hpt363_shared_irq = (pin1 != pin2) ? 1 : 0;
+ if (hpt363_shared_irq) {
+ d->bootable = ON_BOARD;
+ printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
+ }
+ break;
+ }
}
-
- printk("%s: IDE controller on PCI bus %02x dev %02x\n",
- d->name, dev->bus->number, dev->devfn);
+ printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
ide_setup_pci_device(dev, d);
-
- if (dev2 && !hpt363_shared_irq) {
- printk("%s: IDE controller on PCI bus %02x dev %02x\n",
- d2->name, dev2->bus->number, dev2->devfn);
- ide_setup_pci_device(dev2, d2);
- }
+ if (!dev2)
+ return;
+ d2 = d;
+ printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+ ide_setup_pci_device(dev2, d2);
}
/*
drive->waiting_for_dma = 1;
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+ drive->timeout = WAIT_CMD;
+ ide_set_handler(drive, &ide_dma_intr);
OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
IDE_COMMAND_REG);
case ide_dma_begin:
#include <linux/delay.h>
#include <linux/ide.h>
-
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+ if (strstr(id->model, "E X A B Y T E N E S T"))
+ return;
+
id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */
printk("%s: %s, ", drive->name, id->model);
drive->present = 1;
return rc;
}
+/*
+ *
+ */
+static void enable_nest (ide_drive_t *drive)
+{
+ unsigned long timeout;
+
+ printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
+ SELECT_DRIVE(HWIF(drive), drive);
+ ide_delay_50ms();
+ OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+ timeout = jiffies + WAIT_WORSTCASE;
+ do {
+ if (jiffies > timeout) {
+ printk("failed (timeout)\n");
+ return;
+ }
+ ide_delay_50ms();
+ } while (GET_STAT() & BUSY_STAT);
+ ide_delay_50ms();
+ if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
+ printk("failed (status = 0x%02x)\n", GET_STAT());
+ else
+ printk("success\n");
+ if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
+ (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+ }
+}
+
/*
* probe_for_drive() tests for existence of a given drive using do_probe().
*
if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
}
+ if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
+ enable_nest(drive);
if (!drive->present)
return 0; /* drive not found */
if (drive->id == NULL) { /* identification failed? */
#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
+extern byte ali_proc;
int (*ali_display_info)(char *, char **, off_t, int, int) = NULL;
#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_SIS5513
+extern byte sis_proc;
+int (*sis_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern byte via_proc;
+int (*via_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
static int ide_getxdigit(char c)
{
int digit;
}
#endif /* CONFIG_BLK_DEV_IDEPCI */
} else { /* not pci */
-#ifndef CONFIG_Q40
+#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+
+/*
+ * Geert Uytterhoeven
+ *
+ * unless you can explain me what it really does.
+ * On m68k, we don't have outw() and outl() yet,
+ * and I need a good reason to implement it.
+ *
+ * BTW, IMHO the main remaining portability problem with the IDE driver
+ * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
+ *
+ * I think all accesses should be done using
+ *
+ * ide_in[bwl](ide_device_instance, offset)
+ * ide_out[bwl](ide_device_instance, value, offset)
+ *
+ * so the architecture specific code can #define ide_{in,out}[bwl] to the
+ * appropriate function.
+ *
+ */
switch (digits) {
case 2: outb(val, reg);
break;
case 8: outl(val, reg);
break;
}
-#endif /* CONFIG_Q40 */
+#endif /* !__mc68000__ && !CONFIG_APUS */
}
}
}
ent = create_proc_entry("drivers", 0, proc_ide_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, proc_ide_root);
- ent->get_info = via_display_info;
- }
-#endif /* CONFIG_BLK_DEV_VIA82C586 */
#ifdef CONFIG_BLK_DEV_ALI15X3
- if (ali_display_info) {
+ if ((ali_display_info) && (ali_proc)) {
ent = create_proc_entry("ali", 0, proc_ide_root);
ent->get_info = ali_display_info;
}
#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_SIS5513
+ if ((sis_display_info) && (sis_proc)) {
+ ent = create_proc_entry("sis", 0, proc_ide_root);
+ ent->get_info = sis_display_info;
+ }
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+ if ((via_display_info) && (via_proc)) {
+ ent = create_proc_entry("via", 0, proc_ide_root);
+ ent->get_info = via_display_info;
+ }
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
}
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)
+ if ((ali_display_info) && (ali_proc))
remove_proc_entry("ide/ali",0);
#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_SIS5513
+ if ((sis_display_info) && (sis_proc))
+ remove_proc_entry("ide/sis", 0);
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+ if ((via_display_info) && (via_proc))
+ remove_proc_entry("ide/via",0);
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
remove_proc_entry("ide/drivers", 0);
destroy_proc_ide_interfaces();
remove_proc_entry("ide", 0);
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
idetape_discard_data (drive,bcount.all);
- ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);
+ ide_set_handler (drive,&idetape_pc_intr);
return;
}
#if IDETAPE_DEBUG_LOG
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
- ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD); /* And set the interrupt handler again */
+ ide_set_handler (drive,&idetape_pc_intr); /* And set the interrupt handler again */
}
/*
ide_do_reset (drive);
return;
}
- ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD); /* Set the interrupt routine */
+ ide_set_handler(drive, &idetape_pc_intr); /* Set the interrupt routine */
atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
}
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
- ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD);
+ ide_set_handler(drive, &idetape_transfer_pc);
OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
} else {
OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
spin_lock_init(&tape->spinlock);
drive->driver_data = tape;
drive->ready_stat = 0; /* An ATAPI device ignores DRDY */
+ drive->timeout = IDETAPE_WAIT_CMD;
#ifdef CONFIG_BLK_DEV_IDEPCI
/*
* These two ide-pci host adapters appear to need this disabled.
#include <linux/kmod.h>
#endif /* CONFIG_KMOD */
-#ifdef CONFIG_BLK_DEV_VIA82C586
-extern byte fifoconfig; /* defined in via82c586.c used by ide_setup()*/
-#endif
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern byte fifoconfig; /* defined in via82cxxx.c used by ide_setup() */
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
IDE2_MAJOR, IDE3_MAJOR,
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the ide_timer_expiry() handler later on).
*/
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout)
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
}
#endif
hwgroup->handler = handler;
- hwgroup->timer.expires = jiffies + timeout;
+ hwgroup->timer.expires = jiffies + drive->timeout;
add_timer(&(hwgroup->timer));
spin_unlock_irqrestore(&hwgroup->spinlock, flags);
}
static void atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long old_timeout;
byte stat;
SELECT_DRIVE(HWIF(drive),drive);
printk("%s: ATAPI reset complete\n", drive->name);
} else {
if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
- ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+ old_timeout = drive->timeout;
+ drive->timeout = HZ / 20;
+ ide_set_handler (drive, &atapi_reset_pollfunc);
+ drive->timeout = old_timeout;
return; /* continue polling */
}
hwgroup->poll_timeout = 0; /* end of polling */
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
+ unsigned long old_timeout;
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
- ide_set_handler (drive, &reset_pollfunc, HZ/20);
+ old_timeout = drive->timeout;
+ drive->timeout = HZ / 20;
+ ide_set_handler (drive, &reset_pollfunc);
+ drive->timeout = old_timeout;
return; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
unsigned long flags;
ide_hwif_t *hwif = HWIF(drive);
ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long old_timeout;
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+ old_timeout = drive->timeout;
+ drive->timeout = HZ / 20;
+ ide_set_handler (drive, &atapi_reset_pollfunc);
+ drive->timeout = old_timeout;
__restore_flags (flags); /* local CPU only */
return;
}
OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
udelay(10); /* more than enough time */
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler (drive, &reset_pollfunc, HZ/20);
+ old_timeout = drive->timeout;
+ drive->timeout = HZ / 20;
+ ide_set_handler (drive, &reset_pollfunc);
+ drive->timeout = old_timeout;
+
+ /*
+ * Some weird controller like resetting themselves to a strange
+ * state when the disks are reset this way. At least, the Winbond
+ * 553 documentation says that
+ */
+ if (hwif->resetproc != NULL)
+ hwif->resetproc(drive);
+
#endif /* OK_TO_RESET_CONTROLLER */
__restore_flags (flags); /* local CPU only */
*/
void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
- ide_set_handler (drive, handler, WAIT_CMD);
+ ide_set_handler (drive, handler);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
OUT_BYTE(nsect,IDE_NSECTOR_REG);
if (args[0] == WIN_SMART) {
OUT_BYTE(0x4f, IDE_LCYL_REG);
OUT_BYTE(0xc2, IDE_HCYL_REG);
+ OUT_BYTE(args[2],IDE_FEATURE_REG);
+ OUT_BYTE(args[1],IDE_SECTOR_REG);
+ ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ return;
}
OUT_BYTE(args[2],IDE_FEATURE_REG);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
bdev->current_request = hwgroup->rq = drive->queue;
spin_unlock_irqrestore(&io_request_lock, io_flags);
+#if 0
if (hwif->irq != masked_irq)
- disable_irq(hwif->irq);
+ disable_irq_nosync(hwif->irq);
spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
start_request(drive);
spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
if (hwif->irq != masked_irq)
enable_irq(hwif->irq);
+#else
+
+ if (masked_irq && hwif->irq != masked_irq) {
+ printk("%s: (disable_irq) %smasked_irq %d\n",
+ drive->name,
+ masked_irq ? "" : "un_", hwif->irq);
+
+#if 0
+ disable_irq(hwif->irq);
+#else
+ disable_irq_nosync(hwif->irq);
+#endif
+ }
+ spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
+ start_request(drive);
+ spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
+ if (masked_irq && hwif->irq != masked_irq) {
+ printk("%s: (enable_irq) %smasked_irq %d\n",
+ drive->name,
+ masked_irq ? "" : "un_", hwif->irq);
+ enable_irq(hwif->irq);
+ }
+#endif
}
}
}
hwgroup->busy = 1; /* should already be "1" */
hwgroup->handler = NULL;
- del_timer(&hwgroup->timer); /* Is this needed?? */
- if (hwgroup->poll_timeout != 0) { /* polling in progress? */
+ /* polling in progress or just don't timeout */
+ if (hwgroup->poll_timeout != 0) {
spin_unlock_irqrestore(&hwgroup->spinlock, flags);
handler(drive);
} else if (drive_is_ready(drive)) {
}
spin_unlock_irqrestore(&io_request_lock, flags);
do_hwgroup_request(hwgroup);
- if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
+ if (action == ide_wait) {
down(&sem); /* wait for it to be serviced */
+ rq->sem = NULL;
+ }
return rq->errors ? -EIO : 0; /* return -EIO if errors */
}
int ide_config_drive_speed (ide_drive_t *drive, byte speed)
{
+ struct hd_driveid *id = drive->id;
+ unsigned long flags;
int err;
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+
/*
* Don't use ide_wait_cmd here - it will
* attempt to set_geometry and recalibrate,
err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+#if 0
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+#endif
+
+ __restore_flags(flags); /* local CPU only */
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ 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;
+ break;
+ case XFER_UDMA_3:
+ 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;
+ break;
+ case XFER_UDMA_2:
+ if (!((id->dma_ultra >> 8) & 4)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0404;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_UDMA_1:
+ if (!((id->dma_ultra >> 8) & 2)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0202;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_UDMA_0:
+ if (!((id->dma_ultra >> 8) & 1)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0101;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_MW_DMA_2:
+ drive->id->dma_ultra &= ~0xFF00;
+ if (!((id->dma_mword >> 8) & 4)) {
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_mword |= 0x0404;
+ }
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_MW_DMA_1:
+ drive->id->dma_ultra &= ~0xFF00;
+ if (!((id->dma_mword >> 8) & 2)) {
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_mword |= 0x0202;
+ }
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_MW_DMA_0:
+ drive->id->dma_ultra &= ~0xFF00;
+ if (!((id->dma_mword >> 8) & 1)) {
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_mword |= 0x0101;
+ }
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_SW_DMA_2:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ if (!((id->dma_1word >> 8) & 4)) {
+ drive->id->dma_1word &= ~0x0F00;
+ drive->id->dma_1word |= 0x0404;
+ }
+ break;
+ case XFER_SW_DMA_1:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ if (!((id->dma_1word >> 8) & 2)) {
+ drive->id->dma_1word &= ~0x0F00;
+ drive->id->dma_1word |= 0x0202;
+ }
+ break;
+ case XFER_SW_DMA_0:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ if (!((id->dma_1word >> 8) & 1)) {
+ drive->id->dma_1word &= ~0x0F00;
+ drive->id->dma_1word |= 0x0101;
+ }
+ break;
+ default:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ }
+
return(err);
}
}
}
-#if defined(CONFIG_BLK_DEV_VIA82C586)
+#if defined(CONFIG_BLK_DEV_VIA82CXXX)
/*
* Look for drive option "splitfifo=..."
*/
fifoconfig = tmp;
goto done;
}
-#endif /* defined(CONFIG_BLK_DEV_VIA82C586) */
+#endif /* defined(CONFIG_BLK_DEV_VIA82CXXX) */
if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
goto bad_option;
EXPORT_SYMBOL(ide_scan_devices);
EXPORT_SYMBOL(ide_register_subdriver);
EXPORT_SYMBOL(ide_unregister_subdriver);
+EXPORT_SYMBOL(ide_replace_subdriver);
EXPORT_SYMBOL(ide_input_data);
EXPORT_SYMBOL(ide_output_data);
EXPORT_SYMBOL(atapi_input_bytes);
while ((line = next) != NULL) {
if ((next = strchr(line,' ')) != NULL)
*next++ = 0;
- if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '='))
+ if (!strncmp(line,"ide",3) ||
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+ !strncmp(line,"splitfifo",9) ||
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+ (!strncmp(line,"hd",2) && line[2] != '='))
ide_setup(line);
}
}
static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
unsigned int cmd, void *arg);
+static int pcd_packet(struct cdrom_device_info *cdi,
+ struct cdrom_generic_command *cgc);
static int pcd_detect(void);
+static void pcd_probe_capabilities(void);
static void do_pcd_read_drq(void);
static void do_pcd_request(void);
static void do_pcd_read(void);
pcd_drive_reset,
pcd_audio_ioctl,
0, /* dev_ioctl */
- CDC_CLOSE_TRAY |
- CDC_OPEN_TRAY |
- CDC_LOCK |
- CDC_MCN |
- CDC_MEDIA_CHANGED |
- CDC_RESET |
- CDC_PLAY_AUDIO,
- 0
+ CDC_CLOSE_TRAY |
+ CDC_OPEN_TRAY |
+ CDC_LOCK |
+ CDC_MCN |
+ CDC_MEDIA_CHANGED |
+ CDC_RESET |
+ CDC_PLAY_AUDIO |
+ CDC_GENERIC_PACKET |
+ CDC_CD_R |
+ CDC_CD_RW,
+ 0,
+ pcd_packet,
};
static void pcd_init_units( void )
if (pcd_detect()) return -1;
+ /* get the atapi capabilities page */
+ pcd_probe_capabilities();
+
if (register_blkdev(MAJOR_NR,name,&cdrom_fops)) {
printk("pcd: unable to get major number %d\n",MAJOR_NR);
return -1;
return r;
}
+static int pcd_packet(struct cdrom_device_info *cdi,
+ struct cdrom_generic_command *cgc)
+{
+ char *un_cmd;
+ int unit = DEVICE_NR(cdi->dev);
+
+ un_cmd = cgc->cmd;
+ return pcd_atapi(unit,un_cmd,cgc->buflen,cgc->buffer, "generic packet");
+}
+
#define DBMSG(msg) ((verbose>1)?(msg):NULL)
static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
return -1;
}
+static void pcd_probe_capabilities( void )
+
+{ int unit, r;
+ char buffer[32];
+ char cmd[12]={0x5a,1<<3,0x2a,0,0,0,0,18,0,0,0,0};
+
+ for (unit=0;unit<PCD_UNITS;unit++) {
+ if (!PCD.present) continue;
+ r = pcd_atapi(unit,cmd,18, buffer,"mode sense capabilities");
+ if (r) continue;
+ /* we should now have the cap page */
+ if ((buffer[11] & 1) == 0)
+ PCD.info.mask |= CDC_CD_R;
+ if ((buffer[11] & 2) == 0)
+ PCD.info.mask |= CDC_CD_RW;
+ if ((buffer[12] & 1) == 0)
+ PCD.info.mask |= CDC_PLAY_AUDIO;
+ if ((buffer[14] & 1) == 0)
+ PCD.info.mask |= CDC_LOCK;
+ if ((buffer[14] & 8) == 0)
+ PCD.info.mask |= CDC_OPEN_TRAY;
+ if ((buffer[14] >> 6) == 0)
+ PCD.info.mask |= CDC_CLOSE_TRAY;
+ }
+}
+
static int pcd_detect( void )
{ char id[18];
switch (cmd) {
- case CDROMPAUSE:
-
- { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0};
-
- return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO;
- }
-
- case CDROMRESUME:
-
- { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0};
-
- return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO;
- }
-
- case CDROMPLAYMSF:
-
- { char cmd[12]={GPCMD_PLAY_AUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0};
- struct cdrom_msf* msf = (struct cdrom_msf*)arg;
-
- cmd[3] = msf->cdmsf_min0;
- cmd[4] = msf->cdmsf_sec0;
- cmd[5] = msf->cdmsf_frame0;
- cmd[6] = msf->cdmsf_min1;
- cmd[7] = msf->cdmsf_sec1;
- cmd[8] = msf->cdmsf_frame1;
-
- return (pcd_atapi(unit,cmd,0,NULL,"play msf")) * EIO;
- }
-
- case CDROMPLAYBLK:
-
- { char cmd[12]={GPCMD_PLAY_AUDIO_10,0,0,0,0,0,0,0,0,0,0,0};
- struct cdrom_blk* blk = (struct cdrom_blk*)arg;
-
- cmd[2] = blk->from >> 24;
- cmd[3] = blk->from >> 16;
- cmd[4] = blk->from >> 8;
- cmd[5] = blk->from;
- cmd[7] = blk->len >> 8;
- cmd[8] = blk->len;
-
- return (pcd_atapi(unit,cmd,0,NULL,"play block")) * EIO;
- }
-
- case CDROMPLAYTRKIND:
-
- { char cmd[12]={GPCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0};
- struct cdrom_ti* ti = (struct cdrom_ti*)arg;
-
- cmd[4] = ti->cdti_trk0;
- cmd[5] = ti->cdti_ind0;
- cmd[7] = ti->cdti_trk1;
- cmd[8] = ti->cdti_ind1;
-
- return (pcd_atapi(unit,cmd,0,NULL,"play track")) * EIO;
- }
-
case CDROMREADTOCHDR:
{ char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0};
return r * EIO;
}
- case CDROMSTOP:
-
- { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,0,0,0,0,0,0,0,0};
-
- return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO;
- }
-
- case CDROMSTART:
-
- { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,1,0,0,0,0,0,0,0};
-
- return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO;
- }
-
- case CDROMVOLCTRL:
-
- { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0};
- char buffer[32];
- char mask[32];
- struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-
- cmd[2] = 0xe;
- cmd[4] = 28;
-
- if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol"))
- return -EIO;
-
- cmd[2] = 0x4e;
-
- if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol mask"))
- return -EIO;
-
- buffer[0] = 0;
-
- buffer[21] = volctrl->channel0 & mask[21];
- buffer[23] = volctrl->channel1 & mask[23];
- buffer[25] = volctrl->channel2 & mask[25];
- buffer[27] = volctrl->channel3 & mask[27];
-
- cmd[0] = 0x55;
- cmd[1] = 0x10;
-
- return pcd_atapi(unit,cmd,28,buffer,"mode select vol") * EIO;
- }
-
- case CDROMVOLREAD:
-
- { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0};
- char buffer[32];
- struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
- int r;
-
- cmd[2] = 0xe;
- cmd[4] = 28;
-
- r = pcd_atapi(unit,cmd,28,buffer,"mode sense vol read");
-
- volctrl->channel0 = buffer[21];
- volctrl->channel1 = buffer[23];
- volctrl->channel2 = buffer[25];
- volctrl->channel3 = buffer[27];
-
- return r * EIO;
- }
-
-
- case CDROMSUBCHNL:
-
- { char cmd[12]={GPCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0};
- struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
- char buffer[32];
-
- if (pcd_atapi(unit,cmd,16,buffer,"read subchannel"))
- return -EIO;
-
- subchnl->cdsc_audiostatus = buffer[1];
- subchnl->cdsc_format = CDROM_MSF;
- subchnl->cdsc_ctrl = buffer[5] & 0xf;
- subchnl->cdsc_trk = buffer[6];
- subchnl->cdsc_ind = buffer[7];
-
- subchnl->cdsc_reladdr.msf.minute = buffer[13];
- subchnl->cdsc_reladdr.msf.second = buffer[14];
- subchnl->cdsc_reladdr.msf.frame = buffer[15];
- subchnl->cdsc_absaddr.msf.minute = buffer[9];
- subchnl->cdsc_absaddr.msf.second = buffer[10];
- subchnl->cdsc_absaddr.msf.frame = buffer[11];
-
- return 0;
- }
-
default:
return -ENOSYS;
/*
- * linux/drivers/block/pdc202xx.c Version 0.26 May 12, 1999
+ * linux/drivers/block/pdc202xx.c Version 0.27 Sept. 3, 1999
*
- * Copyright (C) 1998-99 Andre Hedrick
- * (hedrick@astro.dyer.vanderbilt.edu)
+ * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
*
* 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.
* = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
*/
+/*
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ */
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include "ide_modes.h"
+
#define PDC202XX_DEBUG_DRIVE_INFO 0
#define PDC202XX_DECODE_REGISTER_INFO 0
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
+ unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK;
int err;
unsigned int drive_conf;
byte drive_pci;
- byte test1, test2, speed;
- byte AP, BP, CP, DP, EP;
+ byte test1, test2, speed = -1;
+ byte AP, BP, CP, DP, TB, TC;
+ unsigned short EP;
+ byte CLKSPD = IN_BYTE(high_16 + 0x11);
int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
- byte udma_33 = ultra ? (inb((dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0;
-
- pci_read_config_byte(dev, 0x50, &EP);
+ byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0;
+
+ /*
+ * Set the control register to use the 66Mhz system
+ * clock for UDMA 3/4 mode operation. If one drive on
+ * a channel is U66 capable but the other isn't we
+ * fall back to U33 mode. The BIOS INT 13 hooks turn
+ * the clock on then off for each read/write issued. I don't
+ * do that here because it would require modifying the
+ * kernel, seperating the fop routines from the kernel or
+ * somehow hooking the fops calls. It may also be possible to
+ * leave the 66Mhz clock on and readjust the timing
+ * parameters.
+ */
+
+ byte mask = hwif->channel ? 0x08 : 0x02;
+ unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10);
+ byte ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+ pci_read_config_word(dev, 0x50, &EP);
+
+ if ((ultra_66) && (EP & c_mask)) {
+#ifdef DEBUG
+ printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary", "Primary");
+ printk(" Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+ /* Primary : zero out second bit */
+ /* Secondary : zero out fourth bit */
+ OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+ } else {
+ if (ultra_66) {
+ /*
+ * check to make sure drive on same channel
+ * is u66 capable
+ */
+ if (hwif->drives[!(drive_number%2)].id) {
+ if ((hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0010) ||
+ (hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0008)) {
+ OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+ } else {
+ OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+ }
+ } else { /* udma4 drive by itself */
+ OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+ }
+ }
+ }
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))
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))
return ide_dma_off;
}
+chipset_is_set:
+
if (drive->media != ide_disk)
return ide_dma_off_quietly;
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;
+ speed = XFER_UDMA_4; TB = 0x20; TC = 0x01;
} 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;
+ speed = XFER_UDMA_3; TB = 0x40; TC = 0x02;
} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
- if (!((id->dma_ultra >> 8) & 4)) {
- drive->id->dma_ultra &= ~0xFF00;
- 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;
+ speed = XFER_UDMA_2; TB = 0x20; TC = 0x01;
} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
- if (!((id->dma_ultra >> 8) & 2)) {
- drive->id->dma_ultra &= ~0xFF00;
- 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;
+ speed = XFER_UDMA_1; TB = 0x40; TC = 0x02;
} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
- if (!((id->dma_ultra >> 8) & 1)) {
- drive->id->dma_ultra &= ~0xFF00;
- 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;
+ speed = XFER_UDMA_0; TB = 0x60; TC = 0x03;
} 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;
+ speed = XFER_MW_DMA_2; TB = 0x60; TC = 0x03;
} 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;
+ speed = XFER_MW_DMA_1; TB = 0x60; TC = 0x04;
} 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;
+ speed = XFER_MW_DMA_0; TB = 0x60; TC = 0x05;
} 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;
+ speed = XFER_SW_DMA_2; TB = 0x60; TC = 0x05;
} 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;
+ speed = XFER_SW_DMA_1; TB = 0x80; TC = 0x06;
} 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;
+ speed = XFER_SW_DMA_0; TB = 0xC0; TC = 0x0B;
} else {
/* restore original pci-config space */
pci_write_config_dword(dev, drive_pci, drive_conf);
return ide_dma_off_quietly;
}
- err = ide_config_drive_speed(drive, speed);
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+ pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
#if PDC202XX_DECODE_REGISTER_INFO
pci_read_config_byte(dev, (drive_pci), &AP);
decode_registers(REG_D, DP);
#endif /* PDC202XX_DECODE_REGISTER_INFO */
+ err = ide_config_drive_speed(drive, speed);
+
#if PDC202XX_DEBUG_DRIVE_INFO
printk("%s: %s drive%d 0x%08x ",
drive->name, ide_xfer_verbose(speed),
* 11, 5, 4, 3, 2, 1, 0
*/
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte drive_pci, speed;
+ byte AP, BP, TA, TB;
+
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ int err;
+
+ switch (drive_number) {
+ case 0: drive_pci = 0x60; break;
+ case 1: drive_pci = 0x64; break;
+ case 2: drive_pci = 0x68; break;
+ case 3: drive_pci = 0x6c; break;
+ default: return 1;
+ }
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+
+ if ((AP & 0x0F) || (BP & 0x07)) {
+ /* clear PIO modes of lower 8421 bits of A Register */
+ pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+
+ /* clear PIO modes of lower 421 bits of B Register */
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ }
+
+ pio = (pio == 5) ? 4 : pio;
+ switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
+ case 4: speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
+ case 3: speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
+ case 2: speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
+ case 1: speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
+ case 0:
+ default: speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
+ }
+ pci_write_config_byte(dev, (drive_pci), AP|TA);
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+
+#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);
+ pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+ 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 */
+
+ err = ide_config_drive_speed(drive, speed);
+
+#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 */
+
+ return err;
+}
+
+static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
+{
+ (void) config_chipset_for_pio(drive, pio);
+}
+
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
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);
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
}
-
+ dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
if (id->dma_ultra & 0x001F) {
/* Force if Capable UltraDMA */
}
} else if (id->field_valid & 2) {
try_dma_modes:
- if ((id->dma_mword & 0x0004) ||
- (id->dma_1word & 0x0004)) {
+ if ((id->dma_mword & 0x0007) ||
+ (id->dma_1word & 0x0007)) {
/* Force if Capable regular DMA modes */
dma_func = config_chipset_for_dma(drive, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ }
+ } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+ if (id->eide_dma_time > 150) {
+ goto no_dma_set;
}
- } 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);
+ 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:
+ (void) config_chipset_for_pio(drive, 5);
}
+
return HWIF(drive)->dmaproc(dma_func, drive);
}
byte primary_mode = inb(high_16 + 0x001a);
byte secondary_mode = inb(high_16 + 0x001b);
+ if (dev->device == PCI_DEVICE_ID_PROMISE_20262) {
+ int i = 0;
+ /*
+ * software reset - this is required because the bios
+ * will set UDMA timing on if the hdd supports it. The
+ * user may want to turn udma off. A bug in the pdc20262
+ * is that it cannot handle a downgrade in timing from UDMA
+ * to DMA. Disk accesses after issuing a set feature command
+ * will result in errors. A software reset leaves the timing
+ * registers intact, but resets the drives.
+ */
+
+ OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+ ide_delay_50ms();
+ ide_delay_50ms();
+ OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+ for (i=0; i<40; i++)
+ ide_delay_50ms();
+ }
+
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
return dev->irq;
}
+unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
+{
+ unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+ unsigned short CIS;
+
+ pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+ return ((CIS & mask) ? 0 : 1);
+}
+
void __init ide_init_pdc202xx (ide_hwif_t *hwif)
{
+ hwif->tuneproc = &pdc202xx_tune_drive;
+
if (hwif->dma_base) {
hwif->dmaproc = &pdc202xx_dmaproc;
-
- switch(hwif->pci_dev->device) {
- case PCI_DEVICE_ID_PROMISE_20262:
-#if 0
- {
- unsigned long high_16 = hwif->pci_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
- hwif->udma_four = 1;
- }
-#endif
- break;
- case PCI_DEVICE_ID_PROMISE_20246:
- default:
- hwif->udma_four = 0;
- break;
- }
+ } else {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
}
}
if (!hwif) return 0;
drive = &hwif->drives[0];
+ drive->timeout = HZ/100;
hwif2 = &ide_hwifs[hwif->index+1];
if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
return 1;
if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
return 0;
}
- OUT_BYTE(0x08,IDE_CONTROL_REG);
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(0x08,IDE_CONTROL_REG);
if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
return 0;
}
unsigned int sectors_left, sectors_avail, nsect;
struct request *rq;
+ /* reset timeout */
+ drive->timeout = HZ/100;
+
if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
ide_error(drive, "promise_read_intr", stat);
return;
if (stat & DRQ_STAT)
goto read_again;
if (stat & BUSY_STAT) {
- ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
+ drive->timeout = WAIT_CMD;
+ ide_set_handler (drive, &promise_read_intr);
#ifdef DEBUG_READ
printk(KERN_DEBUG "%s: promise_read: waiting for"
"interrupt\n", drive->name);
if (GET_STAT() & BUSY_STAT) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- ide_set_handler(drive, &promise_complete_pollfunc, 1);
+ drive->timeout = 1;
+ ide_set_handler(drive, &promise_complete_pollfunc);
return; /* continue polling... */
}
hwgroup->poll_timeout = 0;
if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- ide_set_handler (drive, &promise_write_pollfunc, 1);
+ drive->timeout = 1;
+ ide_set_handler (drive, &promise_write_pollfunc);
return; /* continue polling... */
}
hwgroup->poll_timeout = 0;
*/
ide_multwrite(drive, 4);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler(drive, &promise_complete_pollfunc, 1);
+ drive->timeout = 1;
+ ide_set_handler(drive, &promise_complete_pollfunc);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
drive->name, GET_STAT());
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);
+ drive->timeout = 1;
+ ide_set_handler (drive, &promise_write_pollfunc);
} else {
/*
* There are 4 or fewer sectors to transfer, do them all in one go
*/
ide_multwrite(drive, rq->nr_sectors);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler(drive, &promise_complete_pollfunc, 1);
+ drive->timeout = 1;
+ ide_set_handler(drive, &promise_complete_pollfunc);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
"status = %02x\n", drive->name, GET_STAT());
printk(KERN_DEBUG "%s: read: waiting for "
"interrupt\n", drive->name);
#endif
- ide_set_handler(drive, &promise_read_intr, WAIT_CMD);
+ drive->timeout = WAIT_CMD;
+ ide_set_handler(drive, &promise_read_intr);
return;
}
udelay(1);
/*
- * linux/drivers/block/piix.c Version 0.25 July 11, 1999
+ * linux/drivers/block/piix.c Version 0.27 Sept. 3, 1999
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
+ * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
*
* PIO mode setting function for Intel chipsets.
* For use instead of BIOS settings.
}
}
- if ((id->dma_ultra & 0x0010) && (ultra)) {
- goto backspeed;
- } else if ((id->dma_ultra & 0x0008) && (ultra)) {
- goto backspeed;
- } else if ((id->dma_ultra & 0x0004) && (ultra)) {
-backspeed:
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- if (!((id->dma_ultra >> 8) & 4)) {
- drive->id->dma_ultra &= ~0x0F00;
- drive->id->dma_ultra |= 0x0404;
- }
+ if (((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008) || (id->dma_ultra & 0x0004)) && (ultra)) {
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)) {
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- 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);
}
speed = XFER_UDMA_1;
} else if ((id->dma_ultra & 0x0001) && (ultra)) {
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- 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);
} else if (id->dma_mword & 0x0004) {
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- drive->id->dma_ultra &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- 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) {
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- drive->id->dma_ultra &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- 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) {
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- drive->id->dma_ultra &= ~0x0F00;
- drive->id->dma_mword &= ~0x0F00;
- if (!((id->dma_1word >> 8) & 4)) {
- drive->id->dma_1word &= ~0x0F00;
- drive->id->dma_1word |= 0x0404;
- }
speed = XFER_SW_DMA_2;
} else {
speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
(void) ide_config_drive_speed(drive, speed);
#if PIIX_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d ",
- drive->name,
- ide_xfer_verbose(speed),
- drive_number);
+ printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number);
printk("\n");
#endif /* PIIX_DEBUG_DRIVE_INFO */
}
#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
-void ide_init_piix (ide_hwif_t *hwif)
+void __init ide_init_piix (ide_hwif_t *hwif)
{
hwif->tuneproc = &piix_tune_drive;
/*
- * linux/drivers/block/sis5513.c Version 0.06 July 11, 1999
+ * linux/drivers/block/sis5513.c Version 0.07 Sept. 3, 1999
*
- * Copyright (C) 1999 Andre Hedrick
+ * Copyright (C) 1999 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
*
- * drive_number
- * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ * Thanks to SIS Taiwan for direct support and hardware.
+ * Tested and designed on the SiS620/5513 chipset.
*/
#include <linux/types.h>
#include "ide_modes.h"
+#define SIS5513_DEBUG_DRIVE_INFO 0
+
+#define DISPLAY_SIS_TIMINGS
+
static struct pci_dev *host_dev;
-#define SIS5513_DEBUG_DRIVE_INFO 0
+#if 0
+static struct _pio_mode_mapping {
+ byte data_active;
+ byte recovery;
+ byte pio_mode;
+} pio_mode_mapping[] = {
+ { 8, 12, 0 },
+ { 6, 7, 1 },
+ { 4, 4, 2 },
+ { 3, 3, 3 },
+ { 3, 1, 4 }
+};
+
+static struct _dma_mode_mapping {
+ byte data_active;
+ byte recovery;
+ byte dma_mode;
+} dma_mode_mapping[] = {
+ { 8, 8, 0 },
+ { 3, 2, 1 },
+ { 3, 1, 2 }
+};
+
+static struct _udma_mode_mapping {
+ byte cycle_time;
+ char * udma_mode;
+} udma_mode_mapping[] = {
+ { 8, "Mode 0" },
+ { 6, "Mode 1" },
+ { 4, "Mode 2" },
+ { 3, "Mode 3" },
+ { 2, "Mode 4" },
+ { 0, "Undefined" }
+};
+
+static __inline__ char * find_udma_mode (byte cycle_time)
+{
+ int n;
+
+ for (n = 0; n <= 4; n++)
+ if (udma_mode_mapping[n].cycle_time <= cycle_time)
+ return udma_mode_mapping[n].udma_mode;
+ return udma_mode_mapping[4].udma_mode;
+}
+#endif
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int sis_get_info(char *, char **, off_t, int, int);
+extern int (*sis_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+struct pci_dev *bmide_dev;
+
+static char *cable_type[] = {
+ "80 pins",
+ "40 pins"
+};
+
+static char *recovery_time [] ={
+ "12 PCICLK", "1 PCICLK",
+ "2 PCICLK", "3 PCICLK",
+ "4 PCICLK", "5 PCICLCK",
+ "6 PCICLK", "7 PCICLCK",
+ "8 PCICLK", "9 PCICLCK",
+ "10 PCICLK", "11 PCICLK",
+ "13 PCICLK", "14 PCICLK",
+ "15 PCICLK", "15 PCICLK"
+};
+
+static char *cycle_time [] = {
+ "Undefined", "2 CLCK",
+ "3 CLK", "4 CLK",
+ "5 CLK", "6 CLK",
+ "7 CLK", "8 CLK"
+};
+
+static char *active_time [] = {
+ "8 PCICLK", "1 PCICLCK",
+ "2 PCICLK", "2 PCICLK",
+ "4 PCICLK", "5 PCICLK",
+ "6 PCICLK", "12 PCICLK"
+};
+
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+ int rc;
+ char *p = buffer;
+ byte reg,reg1;
+#if 0
+ byte cyc, rec, act;
+#endif
+ u16 reg2, reg3;
+
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ rc = pci_read_config_byte(bmide_dev, 0x4a, ®);
+ p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n",
+ (reg & 0x02) ? "On" : "Off",
+ (reg & 0x04) ? "On" : "Off");
+
+ rc = pci_read_config_byte(bmide_dev, 0x09, ®);
+ p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+ (reg & 0x01) ? "Native" : "Compatible",
+ (reg & 0x04) ? "Native" : "Compatible");
+
+ rc = pci_read_config_byte(bmide_dev, 0x48, ®);
+ p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
+ (reg & 0x10) ? cable_type[1] : cable_type[0],
+ (reg & 0x20) ? cable_type[1] : cable_type[0]);
+
+ rc = pci_read_config_word(bmide_dev, 0x4c, ®2);
+ rc = pci_read_config_word(bmide_dev, 0x4e, ®3);
+ p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+ reg2, reg3);
+
+ rc = pci_read_config_byte(bmide_dev, 0x4b, ®);
+ p += sprintf(p, "Drvie 0: Postwrite %s \t \t Postwrite %s\n",
+ (reg & 0x10) ? "Enabled" : "Disabled",
+ (reg & 0x40) ? "Enabled" : "Disabled");
+ p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
+ (reg & 0x01) ? "Enabled" : "Disabled",
+ (reg & 0x04) ? "Enabled" : "Disabled");
+
+ rc = pci_read_config_byte(bmide_dev, 0x41, ®);
+ rc = pci_read_config_byte(bmide_dev, 0x45, ®1);
+ p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
+ (reg & 0x80) ? "Enabled" : "Disabled",
+ (reg1 & 0x80) ? "Enabled" : "Disabled");
+ p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n",
+ cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
+ p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n",
+ active_time[(reg & 0x07)], active_time[(reg &0x07)] );
+
+ rc = pci_read_config_byte(bmide_dev, 0x40, ®);
+ rc = pci_read_config_byte(bmide_dev, 0x44, ®1);
+ p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n",
+ recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
+
+
+ rc = pci_read_config_byte(bmide_dev, 0x4b, ®);
+ p += sprintf(p, "Drvie 1: Postwrite %s \t \t Postwrite %s\n",
+ (reg & 0x20) ? "Enabled" : "Disabled",
+ (reg & 0x80) ? "Enabled" : "Disabled");
+ p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
+ (reg & 0x02) ? "Enabled" : "Disabled",
+ (reg & 0x08) ? "Enabled" : "Disabled");
+
+ rc = pci_read_config_byte(bmide_dev, 0x43, ®);
+ rc = pci_read_config_byte(bmide_dev, 0x47, ®1);
+ p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
+ (reg & 0x80) ? "Enabled" : "Disabled",
+ (reg1 & 0x80) ? "Enabled" : "Disabled");
+ p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n",
+ cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
+ p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n",
+ active_time[(reg & 0x07)], active_time[(reg &0x07)] );
+
+ rc = pci_read_config_byte(bmide_dev, 0x42, ®);
+ rc = pci_read_config_byte(bmide_dev, 0x46, ®1);
+ p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n",
+ recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
+ return p-buffer;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+byte sis_proc = 0;
extern char *ide_xfer_verbose (byte xfer_rate);
/*
}
if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) {
- 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;
- }
if (!(test2 & 0x90)) {
pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
pci_write_config_byte(dev, drive_pci|0x01, test2|0x90);
}
speed = XFER_UDMA_4;
} else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) {
- 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;
- }
if (!(test2 & 0xA0)) {
pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0);
}
speed = XFER_UDMA_3;
} else if ((id->dma_ultra & 0x0004) && (ultra)) {
- if (!((id->dma_ultra >> 8) & 4)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0404;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
mask = (four_two) ? 0xB0 : 0xA0;
if (!(test2 & mask)) {
pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
}
speed = XFER_UDMA_2;
} else if ((id->dma_ultra & 0x0002) && (ultra)) {
- if (!((id->dma_ultra >> 8) & 2)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0202;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
mask = (four_two) ? 0xD0 : 0xC0;
if (!(test2 & mask)) {
pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
}
speed = XFER_UDMA_1;
} else if ((id->dma_ultra & 0x0001) && (ultra)) {
- if (!((id->dma_ultra >> 8) & 1)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0101;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
if (!(test2 & unmask)) {
pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
pci_write_config_byte(dev, drive_pci|0x01, test2|unmask);
}
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);
err = ide_config_drive_speed(drive, speed);
#if SIS5513_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d\n",
- drive->name,
- ide_xfer_verbose(speed),
- drive_number);
+ printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number);
#endif /* SIS5513_DEBUG_DRIVE_INFO */
return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
{
struct pci_dev *host;
- byte latency = 0, reg48h = 0;
+ byte latency = 0;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
- pci_read_config_byte(dev, 0x48, ®48h);
for (host = pci_devices; host; host=host->next) {
if (host->vendor == PCI_VENDOR_ID_SI &&
if (latency != 0x10)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
host_dev = host;
- printk("%s: Chipset Core ATA-66, SiS620\n", name);
- printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n",
- name,
- (reg48h & 0x10) ? "33" : "66",
- (reg48h & 0x20) ? "33" : "66");
break;
} else if (host->vendor == PCI_VENDOR_ID_SI &&
host->device == PCI_DEVICE_ID_SI_530) {
host_dev = host;
- printk("%s: Chipset Core ATA-66, SiS530\n", name);
- printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n",
- name,
- (reg48h & 0x10) ? "33" : "66",
- (reg48h & 0x20) ? "33" : "66");
break;
} else if (host->vendor == PCI_VENDOR_ID_SI &&
host->device == PCI_DEVICE_ID_SI_5600) {
host_dev = host;
- printk("SIS5600:%s Chipset Core ATA-33\n", name);
break;
} else if (host->vendor == PCI_VENDOR_ID_SI &&
host->device == PCI_DEVICE_ID_SI_5597) {
host_dev = host;
- printk("SIS5597:%s Chipset Core ATA-33\n", name);
break;
}
}
pci_read_config_byte(dev, 0x52, ®52h);
if (!(reg52h & 0x04))
+ /* set IDE controller to operate in Compabitility mode obly */
pci_write_config_byte(dev, 0x52, reg52h|0x04);
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+ sis_proc = 1;
+ bmide_dev = dev;
+ sis_display_info = &sis_get_info;
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
}
-
return 0;
}
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
+unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
{
- byte reg48h = 0;
+ byte reg48h = 0, ata66 = 0;
byte mask = hwif->channel ? 0x20 : 0x10;
-
pci_read_config_byte(hwif->pci_dev, 0x48, ®48h);
+
+ if (host_dev) {
+ switch(host_dev->device) {
+ case PCI_DEVICE_ID_SI_530:
+ case PCI_DEVICE_ID_SI_620:
+ ata66 = (reg48h & mask) ? 0 : 1;
+ default:
+ break;
+ }
+ }
+ return (ata66);
+}
+
+void __init ide_init_sis5513 (ide_hwif_t *hwif)
+{
+
hwif->irq = hwif->channel ? 15 : 14;
if (!(hwif->dma_base))
switch(host_dev->device) {
case PCI_DEVICE_ID_SI_530:
case PCI_DEVICE_ID_SI_620:
- hwif->autodma = 1;
- hwif->udma_four = (reg48h & mask) ? 0 : 1;
- hwif->dmaproc = &sis5513_dmaproc;
- return;
case PCI_DEVICE_ID_SI_5600:
case PCI_DEVICE_ID_SI_5597:
hwif->autodma = 1;
- hwif->udma_four = 0;
hwif->dmaproc = &sis5513_dmaproc;
- return;
+ break;
default:
hwif->autodma = 0;
- hwif->udma_four = 0;
- return;
+ break;
}
}
+ return;
}
outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+ drive->timeout = WAIT_CMD;
+ ide_set_handler(drive, &ide_dma_intr);
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
return 0;
case ide_dma_begin:
+++ /dev/null
-/*
- * linux/drivers/block/via82c586.c Version 0.04 July 11, 1999
- *
- * Copyright (C) 1998 Michel Aubry, Maintainer
- * Copyright (C) 1998 Andre Hedrick, Maintainer
- *
- * 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 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 <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static struct pci_dev *host_dev;
-static struct pci_dev *isa_dev;
-
-#define DISPLAY_VIA_TIMINGS
-
-#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-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.
- *
- * VIA Apollo chipset has complete support for
- * setting up the timing parameters.
- */
-static void set_via_timings (ide_hwif_t *hwif)
-{
- struct pci_dev *dev = hwif->pci_dev;
- 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);
-
- /*
- * 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++;
-
- 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.
- * (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)))
- errors++;
-
- 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 (!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;
- }
- }
-
- /* 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;
-}
-
-unsigned int __init pci_init_via82c568 (struct pci_dev *dev, const char *name)
-{
- struct pci_dev *host;
- struct pci_dev *isa;
-
- byte revision = 0;
-
- for (host = pci_devices; host; host=host->next) {
- if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C585) {
- host_dev = host;
- printk("VT 82C585 Apollo VP1/VPX");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
- isa_dev = isa;
- pci_read_config_byte(isa_dev, 0x0d, &revision);
- if (revision >= 0x20)
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- } else if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C595) {
- host_dev = host;
- printk("VT 82C595 Apollo VP2");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
- isa_dev = isa;
- pci_read_config_byte(isa_dev, 0x0d, &revision);
- if (revision >= 0x20)
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- } else if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C597_0) {
- host_dev = host;
- printk("VT 82C597 Apollo VP3");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
- isa_dev = isa;
- pci_read_config_byte(isa_dev, 0x0d, &revision);
- if (revision >= 0x20)
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- } else if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C598_0) {
- host_dev = host;
- printk("VT 82C598 Apollo MVP3");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
- isa_dev = isa;
- pci_read_config_byte(isa_dev, 0x0d, &revision);
- if (revision >= 0x20)
- printk(" Chipset Core ATA-33");
- break;
- } else if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C596) {
- isa_dev = isa;
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- } else if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C680) {
- host_dev = host;
- printk("VT 82C680 Apollo P6");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
- isa_dev = isa;
- pci_read_config_byte(isa_dev, 0x0d, &revision);
- if (revision >= 0x20)
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- } else if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C691) {
- host_dev = host;
- printk("VT 82C691 Apollo Pro");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C596) {
- isa_dev = isa;
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- } else if (host->vendor == PCI_VENDOR_ID_VIA &&
- host->device == PCI_DEVICE_ID_VIA_82C693) {
- host_dev = host;
- printk("VT 82C693 Apollo Pro Plus");
- for (isa = pci_devices; isa; isa=isa->next) {
- if (isa->vendor == PCI_VENDOR_ID_VIA &&
- isa->device == PCI_DEVICE_ID_VIA_82C596) {
- isa_dev = isa;
- printk(" Chipset Core ATA-33");
- break;
- }
- }
- printk("\n");
- break;
- }
- }
- return 0;
-}
-
-void __init ide_init_via82c586 (ide_hwif_t *hwif)
-{
- set_via_timings(hwif);
-}
-
-/*
- * 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);
- }
-}
--- /dev/null
+/*
+ * linux/drivers/block/via82cxxx.c Version 0.05 Sept. 03, 1999
+ *
+ * Copyright (C) 1998-99 Michel Aubry, Maintainer
+ * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@pobox.com)
+ * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * The VIA MVP-4 is reported OK with UDMA.
+ * 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 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 <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+static struct pci_dev *host_dev = NULL;
+static struct pci_dev *isa_dev = NULL;
+
+static const struct {
+ const char *name;
+ unsigned short host_id;
+} ApolloHostChipInfo[] = {
+ { "VT 82C585 Apollo VP1/VPX", PCI_DEVICE_ID_VIA_82C585, },
+ { "VT 82C595 Apollo VP2", PCI_DEVICE_ID_VIA_82C595, },
+ { "VT 82C597 Apollo VP3", PCI_DEVICE_ID_VIA_82C597_0, },
+ { "VT 82C598 Apollo MVP3", PCI_DEVICE_ID_VIA_82C598_0, },
+ { "VT 82C680 Apollo P6", PCI_DEVICE_ID_VIA_82C680, },
+ { "VT 82C691 Apollo Pro", PCI_DEVICE_ID_VIA_82C691, },
+ { "VT 82C693 Apollo Pro Plus", PCI_DEVICE_ID_VIA_82C693, },
+ { "Apollo MVP4", PCI_DEVICE_ID_VIA_8501_0, },
+};
+
+#define NUM_APOLLO_ISA_CHIP_DEVICES 2
+#define VIA_FLAG_CHECK_REV 0x00000001
+#define VIA_FLAG_ATA_66 0x00000002
+
+static const struct {
+ unsigned short host_id;
+ unsigned short isa_id;
+ unsigned int flags;
+} ApolloISAChipInfo[] = {
+ { PCI_DEVICE_ID_VIA_82C585, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV },
+ { PCI_DEVICE_ID_VIA_82C595, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV },
+ { PCI_DEVICE_ID_VIA_82C597_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV },
+ { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV },
+ { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C596, 0 },
+ { PCI_DEVICE_ID_VIA_82C680, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV },
+ { PCI_DEVICE_ID_VIA_82C691, PCI_DEVICE_ID_VIA_82C596, 0 },
+ { PCI_DEVICE_ID_VIA_82C693, PCI_DEVICE_ID_VIA_82C596, 0 },
+ { PCI_DEVICE_ID_VIA_8501_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66 },
+};
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+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 via_proc = 0;
+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.
+ *
+ * VIA Apollo chipset has complete support for
+ * setting up the timing parameters.
+ */
+static void set_via_timings (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ 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);
+
+ /*
+ * 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++;
+
+ 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.
+ * (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)))
+ errors++;
+
+ 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 (!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 82cxxx 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;
+ }
+ }
+
+ /* 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)
+ via_proc = 1;
+ bmide_dev = hwif->pci_dev;
+ via_display_info = &via_get_info;
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/
+ return 0;
+}
+
+unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
+{
+ struct pci_dev *host;
+ struct pci_dev *isa;
+ int i, j, ata33, ata66;
+
+ byte revision = 0;
+
+ for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) {
+ host = pci_find_device (PCI_VENDOR_ID_VIA,
+ ApolloHostChipInfo[i].host_id,
+ NULL);
+ if (!host)
+ continue;
+
+ host_dev = host;
+ printk(ApolloHostChipInfo[i].name);
+
+ for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) {
+ if (ApolloISAChipInfo[j].host_id !=
+ ApolloHostChipInfo[i].host_id)
+ continue;
+
+ isa = pci_find_device (PCI_VENDOR_ID_VIA,
+ ApolloISAChipInfo[i].isa_id,
+ NULL);
+ if (!isa)
+ continue;
+
+ isa_dev = isa;
+
+ ata33 = 1;
+ ata66 = 0;
+
+ if (ApolloISAChipInfo[i].flags & VIA_FLAG_CHECK_REV) {
+ pci_read_config_byte(isa_dev, 0x0d, &revision);
+ ata33 = (revision >= 0x20) ? 1 : 0;
+ } else if (ApolloISAChipInfo[i].flags & VIA_FLAG_ATA_66) {
+ ata33 = 0;
+ ata66 = 1;
+ }
+
+ if (ata33 | ata66)
+ printk(" Chipset Core ATA-%s", ata66 ? "66" : "33");
+ }
+ printk("\n");
+ }
+
+ return 0;
+}
+
+unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif)
+{
+ /* (Jeff Garzik) FIXME!!! for MVP4 */
+ return 0;
+}
+
+void __init ide_init_via82cxxx (ide_hwif_t *hwif)
+{
+ set_via_timings(hwif);
+}
+
+/*
+ * 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_via82cxxx (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);
+ }
+}
for ide-cd to handle multisession discs.
-- Export cdrom_mode_sense and cdrom_mode_select.
-- init_cdrom_command() for setting up a cgc command.
+
+ 3.05 Sep 23, 1999 - Jens Axboe <axboe@image.dk>
+ -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually
+ impossible to send the drive data in a sensible way.
+
-------------------------------------------------------------------------*/
-#define REVISION "Revision: 3.04"
-#define VERSION "Id: cdrom.c 3.04 1999/09/14"
+#define REVISION "Revision: 3.05"
+#define VERSION "Id: cdrom.c 3.05 1999/09/23"
/* I use an error-log mask to give fine grain control over the type of
messages dumped to the system logs. The available masks include: */
#include <linux/cdrom.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
+#include <linux/init.h>
#include <asm/fcntl.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
*/
#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
+static int cdrom_setup_writemode(struct cdrom_device_info *cdi);
+
int register_cdrom(struct cdrom_device_info *cdi)
{
static char banner_printed = 0;
if (cdo->open == NULL || cdo->release == NULL)
return -2;
if ( !banner_printed ) {
- printk(KERN_INFO "Uniform CDROM driver " REVISION "\n");
+ printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
banner_printed = 1;
#ifdef CONFIG_SYSCTL
cdrom_sysctl_register();
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
cdi->next = topCdromPtr;
topCdromPtr = cdi;
+ if (CDROM_CAN(CDC_CD_R) || CDROM_CAN(CDC_CD_RW) || CDROM_CAN(CDC_DVD_R))
+ (void)cdrom_setup_writemode(cdi);
+
return 0;
}
#undef ENSURE
unsigned long arg)
{
struct cdrom_device_ops *cdo = cdi->ops;
- kdev_t dev = cdi->dev;
struct cdrom_generic_command cgc;
+ kdev_t dev = cdi->dev;
char buffer[32];
int ret = 0;
case CDROMSTART:
case CDROMSTOP: {
- cdinfo(CD_DO_IOCTL, "entering audio ioctl (start/stop)\n");
+ cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
cgc.cmd[0] = GPCMD_START_STOP_UNIT;
cgc.cmd[1] = 1;
cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
case CDROMPAUSE:
case CDROMRESUME: {
- cdinfo(CD_DO_IOCTL, "entering audio ioctl (pause/resume)\n");
+ cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
cgc.cmd[0] = GPCMD_PAUSE_RESUME;
cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
return cdo->generic_packet(cdi, &cgc);
dvd_struct s;
if (!CDROM_CAN(CDC_DVD))
return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering dvd_read_struct\n");
+ cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
IOCTL_IN(arg, dvd_struct, s);
if ((ret = dvd_read_struct(cdi, &s)))
return ret;
dvd_authinfo ai;
if (!CDROM_CAN(CDC_DVD))
return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering dvd_auth\n");
+ cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n");
IOCTL_IN(arg, dvd_authinfo, ai);
if ((ret = dvd_do_auth (cdi, &ai)))
return ret;
}
case CDROM_SEND_PACKET: {
+ __u8 *userbuf, copy = 0;
if (!CDROM_CAN(CDC_GENERIC_PACKET))
return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering send_packet\n");
+ cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n");
IOCTL_IN(arg, struct cdrom_generic_command, cgc);
- cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
+ copy = !!cgc.buflen;
+ userbuf = cgc.buffer;
+ cgc.buffer = NULL;
+ if (userbuf != NULL && copy) {
+ /* usually commands just copy data one way, i.e.
+ * we send a buffer to the drive and the command
+ * specifies whether the drive will read or
+ * write to that buffer. usually the buffers
+ * are very small, so we don't loose that much
+ * by doing a redundant copy each time. */
+ if (!access_ok(VERIFY_WRITE, userbuf, cgc.buflen)) {
+ printk("can't get write perms\n");
+ return -EFAULT;
+ }
+ if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) {
+ printk("can't get read perms\n");
+ return -EFAULT;
+ }
+ }
+ /* reasonable limits */
+ if (cgc.buflen < 0 || cgc.buflen > 131072) {
+ printk("invalid size given\n");
+ return -EINVAL;
+ }
+ if (copy) {
+ cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
+ if (cgc.buffer == NULL)
+ return -ENOMEM;
+ __copy_from_user(cgc.buffer, userbuf, cgc.buflen);
+ }
ret = cdo->generic_packet(cdi, &cgc);
- if (copy_to_user((void*)arg, cgc.buffer, cgc.buflen))
- ret = -EFAULT;
+ if (copy && !ret)
+ __copy_to_user(userbuf, cgc.buffer, cgc.buflen);
kfree(cgc.buffer);
return ret;
}
case CDROM_NEXT_WRITABLE: {
- long next;
+ long next = 0;
+ cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
if ((ret = cdrom_get_next_writable(dev, &next)))
return ret;
IOCTL_OUT(arg, long, next);
return 0;
}
case CDROM_LAST_WRITTEN: {
- long last;
+ long last = 0;
+ cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
if ((ret = cdrom_get_last_written(dev, &last)))
return ret;
IOCTL_OUT(arg, long, last);
track_information ti;
__u32 last_track;
int ret = -1;
-
+
if (!CDROM_CAN(CDC_GENERIC_PACKET))
goto use_toc;
-
+
if ((ret = cdrom_get_disc_info(dev, &di)))
goto use_toc;
track_information ti;
__u16 last_track;
int ret = -1;
-
+
if (!CDROM_CAN(CDC_GENERIC_PACKET))
goto use_last_written;
}
}
+/* return 0 if succesful and the disc can be considered writeable. */
+static int cdrom_setup_writemode(struct cdrom_device_info *cdi)
+{
+ struct cdrom_generic_command cgc;
+ write_param_page wp;
+ disc_information di;
+ track_information ti;
+ int ret, last_track;
+
+ memset(&di, 0, sizeof(disc_information));
+ memset(&ti, 0, sizeof(track_information));
+ memset(&wp, 0, sizeof(write_param_page));
+
+ if ((ret = cdrom_get_disc_info(cdi->dev, &di)))
+ return ret;
+
+ last_track = (di.last_track_msb << 8) | di.last_track_lsb;
+ if ((ret = cdrom_get_track_info(cdi->dev, last_track, 1, &ti)))
+ return ret;
+
+ init_cdrom_command(&cgc, &wp, 0x3c);
+ if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0)))
+ return ret;
+
+ /* sanity checks */
+ if ((ti.damage && !ti.nwa_v) || ti.blank)
+ return 1;
+
+ cdi->packet_size = wp.packet_size = be32_to_cpu(ti.fixed_packet_size);
+ cdi->nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0;
+ wp.track_mode = ti.track_mode;
+ /* write_type 0 == packet/incremental writing */
+ wp.write_type = 0;
+
+ /* MODE1 or MODE2 writing */
+ switch (ti.data_mode) {
+ case 1: wp.data_block_type = 8; break;
+ case 2: wp.data_block_type = 13; break;
+ default: return 1;
+ }
+
+ if ((ret = cdrom_mode_select(cdi, &cgc)))
+ return ret;
+
+ printk("%s: writeable with %s packets of %lu in length", cdi->name,
+ wp.fp ? "fixed" : "variable",
+ (unsigned long)cdi->packet_size);
+ printk(", nwa = %lu\n", (unsigned long)cdi->nwa);
+
+ return 0;
+}
+
EXPORT_SYMBOL(cdrom_get_next_writable);
EXPORT_SYMBOL(cdrom_get_last_written);
EXPORT_SYMBOL(cdrom_count_tracks);
initialized = 1;
}
-#ifdef MODULE
static void cdrom_sysctl_unregister(void)
{
unregister_sysctl_table(cdrom_sysctl_header);
}
-#endif /* endif MODULE */
#endif /* endif CONFIG_SYSCTL */
#ifdef MODULE
-
int init_module(void)
{
#ifdef CONFIG_SYSCTL
cdrom_sysctl_register();
-#endif /* CONFIG_SYSCTL */
+#endif
return 0;
}
cdrom_sysctl_unregister();
#endif /* CONFIG_SYSCTL */
}
-
#endif /* endif MODULE */
+
endif
ifeq ($(CONFIG_COMPUTONE),y)
-L_OBJS += ip2.o ip2main.o
+O_OBJS += ip2.o ip2main.o
else
ifeq ($(CONFIG_COMPUTONE),m)
M_OBJS += ip2.o ip2main.o
endif
ifeq ($(CONFIG_SX),y)
-L_OBJS += sx.o generic_serial.o
+O_OBJS += sx.o generic_serial.o
else
ifeq ($(CONFIG_SX),m)
M_OBJS += sx.o
#include <linux/serial.h>
#include <linux/cdk.h>
#include <linux/comstats.h>
+#include <linux/version.h>
#include <linux/istallion.h>
#include <linux/ioport.h>
#include <linux/delay.h>
ch->blocked_open = 0;
ch->callout_termios = pcxe_callout.init_termios;
ch->normal_termios = pcxe_driver.init_termios;
- init_waitqueue_head(ch->open_wait);
- init_waitqueue_head(ch->close_wait);
+ init_waitqueue_head(&ch->open_wait);
+ init_waitqueue_head(&ch->close_wait);
ch->asyncflags = 0;
}
static __u8 rdsin=0,rdsout=0,rdsstat=0;
static unsigned char rdsbuf[RDS_BUFFER];
static int cadet_lock=0;
+static int cadet_probe(void);
/*
* Signal Strength Threshold Values
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/version.h> /* for linux/stallion.h */
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/tty_flip.h>
dep_tristate ' I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
dep_tristate ' I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
-dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
+if [ "$CONFIG_NET" = "y" ]; then
+ dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
+fi
dep_tristate ' I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI
dep_tristate ' I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O
static int __init baycom_par_setup(char *str)
{
- static unsigned __initdata nr_dev = 0;
+ static unsigned nr_dev = 0;
int ints[2];
if (nr_dev >= NR_PORTS)
static int __init sm_setup(char *str)
{
- static unsigned __initdata nr_dev = 0;
+ static unsigned nr_dev = 0;
int ints[8];
if (nr_dev >= NR_PORTS)
#endif /* MODULE */
#else /* CONFIG_INET */
-EXPORT_SYMBOL(slhc_init);
-EXPORT_SYMBOL(slhc_free);
-EXPORT_SYMBOL(slhc_remember);
-EXPORT_SYMBOL(slhc_compress);
-EXPORT_SYMBOL(slhc_uncompress);
-EXPORT_SYMBOL(slhc_toss);
int
slhc_toss(struct slcompress *comp)
printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
return NULL;
}
+EXPORT_SYMBOL(slhc_init);
+EXPORT_SYMBOL(slhc_free);
+EXPORT_SYMBOL(slhc_remember);
+EXPORT_SYMBOL(slhc_compress);
+EXPORT_SYMBOL(slhc_uncompress);
+EXPORT_SYMBOL(slhc_toss);
#endif /* CONFIG_INET */
*/
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs },
+ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton },
/* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $
* linux/kernel/atp870u.c
*
- * Copyright (C) 1997 Wu Ching Chen
+ * Copyright (C) 1997 Wu Ching Chen
* 2.1.x update (C) 1998 Krzysztof G. Baranowski
*
* Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes
#include<linux/stat.h>
-struct proc_dir_entry proc_scsi_atp870u = {
- PROC_SCSI_ATP870U, 7, "atp870u",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
+struct proc_dir_entry proc_scsi_atp870u =
+{
+ PROC_SCSI_ATP870U, 7, "atp870u",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
};
void mydlyu(unsigned int);
+
/*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
-*/
-
-static unsigned char admaxu=1,host_idu[2],chip_veru[2],scam_on[2],global_map[2];
-static unsigned short int active_idu[2],wide_idu[2],sync_idu,ultra_map[2];
-static int workingu[2]={0,0};
-static Scsi_Cmnd *querequ[2][qcnt],*curr_req[2][16];
-static unsigned char devspu[2][16] = {{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
- 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
- {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
- 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}};
-static unsigned char dirctu[2][16],last_cmd[2],in_snd[2],in_int[2];
+ * static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
+ */
+
+static unsigned char admaxu = 1, host_idu[2], chip_veru[2], scam_on[2], global_map[2];
+static unsigned short int active_idu[2], wide_idu[2], sync_idu, ultra_map[2];
+static int workingu[2] = {0, 0};
+
+static Scsi_Cmnd *querequ[2][qcnt], *curr_req[2][16];
+
+static unsigned char devspu[2][16] = {
+ {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20},
+ {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}
+};
+
+static unsigned char dirctu[2][16], last_cmd[2], in_snd[2], in_int[2];
static unsigned char ata_cdbu[2][16];
-static unsigned int ioportu[2]={0,0};
-static unsigned int irqnumu[2]={0,0};
+static unsigned int ioportu[2] = {0, 0};
+static unsigned int irqnumu[2] = {0, 0};
static unsigned short int pciportu[2];
-static unsigned long prdaddru[2][16],tran_lenu[2][16],last_lenu[2][16];
+static unsigned long prdaddru[2][16], tran_lenu[2][16], last_lenu[2][16];
static unsigned char prd_tableu[2][16][1024];
static unsigned char *prd_posu[2][16];
-static unsigned char quhdu[2],quendu[2];
-static unsigned char devtypeu[2][16] = {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
- { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
-static struct Scsi_Host * atp_host[2]={NULL,NULL};
+static unsigned char quhdu[2], quendu[2];
+
+static unsigned char devtypeu[2][16] =
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static struct Scsi_Host *atp_host[2] = {NULL, NULL};
static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned long flags;
- unsigned short int tmpcip,id;
- unsigned char i,j,h,tarid,lun;
- unsigned char *prd;
- Scsi_Cmnd *workrequ;
- unsigned int workportu,tmport;
- unsigned long adrcntu,k;
- int errstus;
-
- for ( h=0; h < 2; h++ )
- {
- if ( ( irq & 0x0f ) == irqnumu[h] )
- {
- goto irq_numok;
+ unsigned long flags;
+ unsigned short int tmpcip, id;
+ unsigned char i, j, h, tarid, lun;
+ unsigned char *prd;
+ Scsi_Cmnd *workrequ;
+ unsigned int workportu, tmport;
+ unsigned long adrcntu, k;
+ int errstus;
+
+ for (h = 0; h < 2; h++) {
+ if (irq == irqnumu[h]) {
+ goto irq_numok;
+ }
}
- }
- return;
+ return;
irq_numok:
- in_int[h]=1;
- workportu=ioportu[h];
- tmport=workportu;
-
- if ( workingu[h] != 0 )
- {
- tmport += 0x1f;
- j=inb(tmport);
- tmpcip=pciportu[h];
- if ((inb(tmpcip) & 0x08) != 0)
- {
- tmpcip += 0x2;
- while((inb(tmpcip) & 0x08) != 0);
- }
- tmpcip=pciportu[h];
- outb(0x00,tmpcip);
- tmport -=0x08;
- i=inb(tmport);
- if ((j & 0x40) == 0)
- {
- if ((last_cmd[h] & 0x40) == 0)
- {
- last_cmd[h]=0xff;
- }
- }
- else
- {
- last_cmd[h] |= 0x40;
- }
- tmport -= 0x02;
- tarid=inb(tmport);
- tmport += 0x02;
- if ((tarid & 0x40) != 0)
- {
- tarid=(tarid & 0x07) | 0x08;
- }
- else
- {
- tarid &= 0x07;
- }
- if ( i == 0x85 )
- {
- if (wide_idu[h] != 0)
- {
- tmport=workportu+0x1b;
- j=inb(tmport) & 0x0e;
- j |= 0x01;
- outb(j,tmport);
- }
- if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
- (in_snd[h] == 0))
- {
- send_s870(h);
- }
- in_int[h]=0;
- return;
- }
- if ( i == 0x21 )
- {
- tmport -= 0x05;
- adrcntu=0;
- ((unsigned char *)&adrcntu)[2]=inb(tmport++);
- ((unsigned char *)&adrcntu)[1]=inb(tmport++);
- ((unsigned char *)&adrcntu)[0]=inb(tmport);
- k=last_lenu[h][tarid];
- k -= adrcntu;
- tran_lenu[h][tarid]= k;
- last_lenu[h][tarid]=adrcntu;
- tmport -= 0x04;
- outb(0x41,tmport);
- tmport += 0x08;
- outb(0x08,tmport);
- in_int[h]=0;
- return ;
- }
-
- if ((i == 0x80) || (i == 0x8f))
- {
- lun=0;
- tmport -= 0x07;
- j=inb(tmport);
- if ( j == 0x44 )
- {
- tmport += 0x0d;
- lun=inb(tmport) & 0x07;
- }
- else
- {
- if ( j == 0x41 )
- {
+ in_int[h] = 1;
+ workportu = ioportu[h];
+ tmport = workportu;
+
+ if (workingu[h] != 0)
+ {
+ tmport += 0x1f;
+ j = inb(tmport);
+
+ tmpcip = pciportu[h];
+ if ((inb(tmpcip) & 0x08) != 0)
+ {
+ tmpcip += 0x2;
+ while ((inb(tmpcip) & 0x08) != 0);
+ }
+ tmpcip = pciportu[h];
+ outb(0x00, tmpcip);
+ tmport -= 0x08;
+
+ i = inb(tmport);
+ if ((j & 0x40) == 0)
+ {
+ if ((last_cmd[h] & 0x40) == 0)
+ {
+ last_cmd[h] = 0xff;
+ }
+ }
+ else last_cmd[h] |= 0x40;
+
+ tmport -= 0x02;
+ tarid = inb(tmport);
tmport += 0x02;
- adrcntu=0;
- ((unsigned char *)&adrcntu)[2]=inb(tmport++);
- ((unsigned char *)&adrcntu)[1]=inb(tmport++);
- ((unsigned char *)&adrcntu)[0]=inb(tmport);
- k=last_lenu[h][tarid];
- k -= adrcntu;
- tran_lenu[h][tarid]= k;
- last_lenu[h][tarid]=adrcntu;
- tmport += 0x04;
- outb(0x08,tmport);
- in_int[h]=0;
- return ;
- }
- else
- {
- outb(0x46,tmport);
- dirctu[h][tarid]=0x00;
+
+ if ((tarid & 0x40) != 0) {
+ tarid = (tarid & 0x07) | 0x08;
+ } else {
+ tarid &= 0x07;
+ }
+ if (i == 0x85)
+ {
+ if (wide_idu[h] != 0)
+ {
+ tmport = workportu + 0x1b;
+ j = inb(tmport) & 0x0e;
+ j |= 0x01;
+ outb(j, tmport);
+ }
+ if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
+ (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ in_int[h] = 0;
+ return;
+ }
+ if (i == 0x21)
+ {
+ tmport -= 0x05;
+ adrcntu = 0;
+ ((unsigned char *) &adrcntu)[2] = inb(tmport++);
+ ((unsigned char *) &adrcntu)[1] = inb(tmport++);
+ ((unsigned char *) &adrcntu)[0] = inb(tmport);
+ k = last_lenu[h][tarid];
+ k -= adrcntu;
+ tran_lenu[h][tarid] = k;
+ last_lenu[h][tarid] = adrcntu;
+ tmport -= 0x04;
+ outb(0x41, tmport);
+ tmport += 0x08;
+ outb(0x08, tmport);
+ in_int[h] = 0;
+ return;
+ }
+ if ((i == 0x80) || (i == 0x8f))
+ {
+ lun = 0;
+ tmport -= 0x07;
+ j = inb(tmport);
+ if (j == 0x44) {
+ tmport += 0x0d;
+ lun = inb(tmport) & 0x07;
+ } else {
+ if (j == 0x41)
+ {
+ tmport += 0x02;
+ adrcntu = 0;
+ ((unsigned char *) &adrcntu)[2] = inb(tmport++);
+ ((unsigned char *) &adrcntu)[1] = inb(tmport++);
+ ((unsigned char *) &adrcntu)[0] = inb(tmport);
+ k = last_lenu[h][tarid];
+ k -= adrcntu;
+ tran_lenu[h][tarid] = k;
+ last_lenu[h][tarid] = adrcntu;
+ tmport += 0x04;
+ outb(0x08, tmport);
+ in_int[h] = 0;
+ return;
+ }
+ else
+ {
+ outb(0x46, tmport);
+ dirctu[h][tarid] = 0x00;
+ tmport += 0x02;
+ outb(0x00, tmport++);
+ outb(0x00, tmport++);
+ outb(0x00, tmport++);
+ tmport += 0x03;
+ outb(0x08, tmport);
+ in_int[h] = 0;
+ return;
+ }
+ }
+ tmport = workportu + 0x10;
+ outb(0x45, tmport);
+ tmport += 0x06;
+ tarid = inb(tmport);
+ if ((tarid & 0x10) != 0)
+ {
+ tarid = (tarid & 0x07) | 0x08;
+ } else {
+ tarid &= 0x07;
+ }
+ workrequ = curr_req[h][tarid];
+ tmport = workportu + 0x0f;
+ outb(lun, tmport);
+ tmport += 0x02;
+ outb(devspu[h][tarid], tmport++);
+ adrcntu = tran_lenu[h][tarid];
+ k = last_lenu[h][tarid];
+ outb(((unsigned char *) &k)[2], tmport++);
+ outb(((unsigned char *) &k)[1], tmport++);
+ outb(((unsigned char *) &k)[0], tmport++);
+ j = tarid;
+ if (tarid > 7) {
+ j = (j & 0x07) | 0x40;
+ }
+ j |= dirctu[h][tarid];
+ outb(j, tmport++);
+ outb(0x80, tmport);
+ tmport = workportu + 0x1b;
+ j = inb(tmport) & 0x0e;
+ id = 1;
+ id = id << tarid;
+ if ((id & wide_idu[h]) != 0) {
+ j |= 0x01;
+ }
+ outb(j, tmport);
+ if (last_lenu[h][tarid] == 0) {
+ tmport = workportu + 0x18;
+ outb(0x08, tmport);
+ in_int[h] = 0;
+ return;
+ }
+ prd = prd_posu[h][tarid];
+ while (adrcntu != 0)
+ {
+ id = ((unsigned short int *) (prd))[2];
+ if (id == 0) {
+ k = 0x10000;
+ } else {
+ k = id;
+ }
+ if (k > adrcntu) {
+ ((unsigned short int *) (prd))[2] = (unsigned short int)
+ (k - adrcntu);
+ ((unsigned long *) (prd))[0] += adrcntu;
+ adrcntu = 0;
+ prd_posu[h][tarid] = prd;
+ } else {
+ adrcntu -= k;
+ prdaddru[h][tarid] += 0x08;
+ prd += 0x08;
+ if (adrcntu == 0) {
+ prd_posu[h][tarid] = prd;
+ }
+ }
+ }
+ tmpcip = pciportu[h] + 0x04;
+ outl(prdaddru[h][tarid], tmpcip);
+ tmpcip -= 0x02;
+ outb(0x06, tmpcip);
+ outb(0x00, tmpcip);
+ tmpcip -= 0x02;
+ tmport = workportu + 0x18;
+ if (dirctu[h][tarid] != 0) {
+ outb(0x08, tmport);
+ outb(0x01, tmpcip);
+ in_int[h] = 0;
+ return;
+ }
+ outb(0x08, tmport);
+ outb(0x09, tmpcip);
+ in_int[h] = 0;
+ return;
+ }
+ workrequ = curr_req[h][tarid];
+ if (i == 0x42) {
+ errstus = 0x02;
+ workrequ->result = errstus;
+ goto go_42;
+ }
+ if (i == 0x16)
+ {
+ errstus = 0;
+ tmport -= 0x08;
+ errstus = inb(tmport);
+ workrequ->result = errstus;
+go_42:
+ spin_lock_irqsave(&io_request_lock, flags);
+ (*workrequ->scsi_done) (workrequ);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ curr_req[h][tarid] = 0;
+ workingu[h]--;
+ if (wide_idu[h] != 0) {
+ tmport = workportu + 0x1b;
+ j = inb(tmport) & 0x0e;
+ j |= 0x01;
+ outb(j, tmport);
+ }
+ if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
+ (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ in_int[h] = 0;
+ return;
+ }
+ if (i == 0x4f) {
+ i = 0x89;
+ }
+ i &= 0x0f;
+ if (i == 0x09) {
+ tmpcip = tmpcip + 4;
+ outl(prdaddru[h][tarid], tmpcip);
+ tmpcip = tmpcip - 2;
+ outb(0x06, tmpcip);
+ outb(0x00, tmpcip);
+ tmpcip = tmpcip - 2;
+ tmport = workportu + 0x10;
+ outb(0x41, tmport);
+ dirctu[h][tarid] = 0x00;
+ tmport += 0x08;
+ outb(0x08, tmport);
+ outb(0x09, tmpcip);
+ in_int[h] = 0;
+ return;
+ }
+ if (i == 0x08) {
+ tmpcip = tmpcip + 4;
+ outl(prdaddru[h][tarid], tmpcip);
+ tmpcip = tmpcip - 2;
+ outb(0x06, tmpcip);
+ outb(0x00, tmpcip);
+ tmpcip = tmpcip - 2;
+ tmport = workportu + 0x10;
+ outb(0x41, tmport);
+ tmport += 0x05;
+ outb((unsigned char) (inb(tmport) | 0x20), tmport);
+ dirctu[h][tarid] = 0x20;
+ tmport += 0x03;
+ outb(0x08, tmport);
+ outb(0x01, tmpcip);
+ in_int[h] = 0;
+ return;
+ }
+ tmport -= 0x07;
+ if (i == 0x0a) {
+ outb(0x30, tmport);
+ } else {
+ outb(0x46, tmport);
+ }
+ dirctu[h][tarid] = 0x00;
tmport += 0x02;
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- tmport+=0x03;
- outb(0x08,tmport);
- in_int[h]=0;
+ outb(0x00, tmport++);
+ outb(0x00, tmport++);
+ outb(0x00, tmport++);
+ tmport += 0x03;
+ outb(0x08, tmport);
+ in_int[h] = 0;
return;
- }
- }
- tmport=workportu + 0x10;
- outb(0x45,tmport);
- tmport += 0x06;
- tarid=inb(tmport);
- if ((tarid & 0x10) != 0)
- {
- tarid=(tarid & 0x07) | 0x08;
- }
- else
- {
- tarid &= 0x07;
- }
- workrequ=curr_req[h][tarid];
- tmport=workportu + 0x0f;
- outb(lun,tmport);
- tmport += 0x02;
- outb(devspu[h][tarid],tmport++);
- adrcntu=tran_lenu[h][tarid];
- k=last_lenu[h][tarid];
- outb(((unsigned char *)&k)[2],tmport++);
- outb(((unsigned char *)&k)[1],tmport++);
- outb(((unsigned char *)&k)[0],tmport++);
- j=tarid;
- if ( tarid > 7 )
- {
- j = (j & 0x07) | 0x40;
- }
- j |= dirctu[h][tarid];
- outb(j,tmport++);
- outb(0x80,tmport);
- tmport=workportu + 0x1b;
- j=inb(tmport) & 0x0e;
- id=1;
- id=id << tarid;
- if ((id & wide_idu[h]) != 0)
- {
- j |= 0x01;
- }
- outb(j,tmport);
- if ( last_lenu[h][tarid] == 0 )
- {
- tmport=workportu + 0x18;
- outb(0x08,tmport);
- in_int[h]=0;
- return ;
- }
- prd=prd_posu[h][tarid];
- while ( adrcntu != 0 )
- {
- id=((unsigned short int *)(prd))[2];
- if ( id == 0 )
- {
- k=0x10000;
- }
- else
- {
- k=id;
- }
- if ( k > adrcntu )
- {
- ((unsigned short int *)(prd))[2] =(unsigned short int)
- (k - adrcntu);
- ((unsigned long *)(prd))[0] += adrcntu;
- adrcntu=0;
- prd_posu[h][tarid]=prd;
- }
- else
- {
- adrcntu -= k;
- prdaddru[h][tarid] += 0x08;
- prd += 0x08;
- if ( adrcntu == 0 )
- {
- prd_posu[h][tarid]=prd;
- }
- }
- }
- tmpcip=pciportu[h] + 0x04;
- outl(prdaddru[h][tarid],tmpcip);
- tmpcip -= 0x02;
- outb(0x06,tmpcip);
- outb(0x00,tmpcip);
- tmpcip -= 0x02;
- tmport=workportu + 0x18;
- if ( dirctu[h][tarid] != 0 )
- {
- outb(0x08,tmport);
- outb(0x01,tmpcip);
- in_int[h]=0;
- return;
- }
- outb(0x08,tmport);
- outb(0x09,tmpcip);
- in_int[h]=0;
- return;
- }
-
- workrequ=curr_req[h][tarid];
- if ( i == 0x42 )
- {
- errstus=0x02;
- workrequ->result=errstus;
- goto go_42;
- }
- if ( i == 0x16 )
- {
- errstus=0;
- tmport -= 0x08;
- errstus=inb(tmport);
- workrequ->result=errstus;
-/* if ( errstus == 0x02 )
- {
- tmport +=0x10;
- if ((inb(tmport) & 0x80) != 0)
- {
- printk(" autosense ");
- }
- tmport -=0x09;
- outb(0,tmport);
- tmport=workportu+0x3a;
- outb((unsigned char)(inb(tmport) | 0x10),tmport);
- tmport -= 0x39;
-
- outb(0x08,tmport++);
- outb(0x7f,tmport++);
- outb(0x03,tmport++);
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- outb(0x0e,tmport++);
- outb(0x00,tmport);
- tmport+=0x07;
- outb(0x00,tmport++);
- tmport++;
- outb(devspu[h][workrequ->target],tmport++);
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- outb(0x0e,tmport++);
- tmport+=0x03;
- outb(0x09,tmport);
- tmport+=0x07;
- i=0;
- adrcntu=(unsigned long)(&workrequ->sense_buffer[0]);
-get_sens:
- j=inb(tmport);
- if ((j & 0x01) != 0)
- {
- tmport-=0x06;
- (unsigned char)(((caddr_t) adrcntu)[i++])=inb(tmport);
- tmport+=0x06;
- goto get_sens;
- }
- if ((j & 0x80) == 0)
- {
- goto get_sens;
- }
- if ((j & 0x40) == 0)
- {
- tmport-=0x08;
- i=inb(tmport);
- }
- tmport=workportu+0x3a;
- outb((unsigned char)(inb(tmport) & 0xef),tmport);
- tmport=workportu+0x01;
- outb(0x2c,tmport);
- tmport += 0x15;
- outb(0x80,tmport);
- } */
-go_42:
- spin_lock_irqsave(&io_request_lock, flags);
- (*workrequ->scsi_done)(workrequ);
- spin_unlock_irqrestore(&io_request_lock, flags);
-
- curr_req[h][tarid]=0;
- workingu[h]--;
- if (wide_idu[h] != 0)
- {
- tmport=workportu+0x1b;
- j=inb(tmport) & 0x0e;
- j |= 0x01;
- outb(j,tmport);
- }
- if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
- (in_snd[h] == 0))
- {
- send_s870(h);
- }
- in_int[h]=0;
- return;
- }
- if ( i == 0x4f )
- {
- i=0x89;
- }
- i &= 0x0f;
- if ( i == 0x09 )
- {
- tmpcip=tmpcip+4;
- outl(prdaddru[h][tarid],tmpcip);
- tmpcip=tmpcip-2;
- outb(0x06,tmpcip);
- outb(0x00,tmpcip);
- tmpcip=tmpcip-2;
- tmport=workportu+0x10;
- outb(0x41,tmport);
- dirctu[h][tarid]=0x00;
- tmport += 0x08;
- outb(0x08,tmport);
- outb(0x09,tmpcip);
- in_int[h]=0;
- return;
- }
- if ( i == 0x08 )
- {
- tmpcip=tmpcip+4;
- outl(prdaddru[h][tarid],tmpcip);
- tmpcip=tmpcip-2;
- outb(0x06,tmpcip);
- outb(0x00,tmpcip);
- tmpcip=tmpcip-2;
- tmport=workportu+0x10;
- outb(0x41,tmport);
- tmport += 0x05;
- outb((unsigned char)(inb(tmport) | 0x20),tmport);
- dirctu[h][tarid]=0x20;
- tmport += 0x03;
- outb(0x08,tmport);
- outb(0x01,tmpcip);
- in_int[h]=0;
- return;
- }
- tmport -= 0x07;
- if ( i == 0x0a )
- {
- outb(0x30,tmport);
- }
- else
- {
- outb(0x46,tmport);
- }
- dirctu[h][tarid]=0x00;
- tmport += 0x02;
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- outb(0x00,tmport++);
- tmport+=0x03;
- outb(0x08,tmport);
- in_int[h]=0;
- return;
- }
- else
- {
- tmport=workportu+0x17;
- inb(tmport);
- workingu[h]=0;
- in_int[h]=0;
- return;
- }
+ } else {
+ tmport = workportu + 0x17;
+ inb(tmport);
+ workingu[h] = 0;
+ in_int[h] = 0;
+ return;
+ }
}
-int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done)(Scsi_Cmnd *))
+int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *))
{
- unsigned char i,h;
- unsigned long flags;
- unsigned short int m;
- unsigned int tmport;
-
- for( h=0; h <= admaxu; h++ )
- {
- if ( req_p->host == atp_host[h] )
- {
- goto host_ok;
- }
- }
- return 0;
+ unsigned char i, h;
+ unsigned long flags;
+ unsigned short int m;
+ unsigned int tmport;
+
+ for (h = 0; h <= admaxu; h++) {
+ if (req_p->host == atp_host[h]) {
+ goto host_ok;
+ }
+ }
+ return 0;
host_ok:
- if ( req_p->channel != 0 )
- {
- req_p->result = 0x00040000;
- done(req_p);
- return 0;
- }
- m=1;
- m= m << req_p->target;
- if ( ( m & active_idu[h] ) == 0 )
- {
- req_p->result = 0x00040000;
- done(req_p);
- return 0;
- }
- if (done)
- {
- req_p->scsi_done = done;
- }
- else
- {
- printk("atp870u_queuecommand: done can't be NULL\n");
- req_p->result = 0;
- done(req_p);
- return 0;
- }
- quendu[h]++;
- if ( quendu[h] >= qcnt )
- {
- quendu[h]=0;
- }
- wait_que_empty:
- if ( quhdu[h] == quendu[h] )
- {
- goto wait_que_empty;
- }
- save_flags(flags);
- cli();
- querequ[h][quendu[h]]=req_p;
- if ( quendu[h] == 0 )
- {
- i=qcnt-1;
- }
- else
- {
- i=quendu[h]-1;
- }
- tmport = ioportu[h]+0x1c;
- restore_flags(flags);
- if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0))
- {
- send_s870(h);
- }
- return 0;
+ if (req_p->channel != 0) {
+ req_p->result = 0x00040000;
+ done(req_p);
+ return 0;
+ }
+ m = 1;
+ m = m << req_p->target;
+ if ((m & active_idu[h]) == 0) {
+ req_p->result = 0x00040000;
+ done(req_p);
+ return 0;
+ }
+ if (done) {
+ req_p->scsi_done = done;
+ } else {
+ printk("atp870u_queuecommand: done can't be NULL\n");
+ req_p->result = 0;
+ done(req_p);
+ return 0;
+ }
+ quendu[h]++;
+ if (quendu[h] >= qcnt) {
+ quendu[h] = 0;
+ }
+wait_que_empty:
+ if (quhdu[h] == quendu[h]) {
+ goto wait_que_empty;
+ }
+ save_flags(flags);
+ cli();
+ querequ[h][quendu[h]] = req_p;
+ if (quendu[h] == 0) {
+ i = qcnt - 1;
+ } else {
+ i = quendu[h] - 1;
+ }
+ tmport = ioportu[h] + 0x1c;
+ restore_flags(flags);
+ if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0)) {
+ send_s870(h);
+ }
+ return 0;
}
-void mydlyu(unsigned int dlycnt )
+void mydlyu(unsigned int dlycnt)
{
- unsigned int i ;
- for ( i = 0 ; i < dlycnt ; i++ )
- {
- inb(0x80);
- }
+ unsigned int i;
+ for (i = 0; i < dlycnt; i++) {
+ inb(0x80);
+ }
}
void send_s870(unsigned char h)
{
- unsigned int tmport;
- Scsi_Cmnd *workrequ;
- unsigned long flags;
- unsigned int i;
- unsigned char j,tarid;
- unsigned char *prd;
- unsigned short int tmpcip,w;
- unsigned long l,bttl;
- unsigned int workportu;
- struct scatterlist * sgpnt;
+ unsigned int tmport;
+ Scsi_Cmnd *workrequ;
+ unsigned long flags;
+ unsigned int i;
+ unsigned char j, tarid;
+ unsigned char *prd;
+ unsigned short int tmpcip, w;
+ unsigned long l, bttl;
+ unsigned int workportu;
+ struct scatterlist *sgpnt;
save_flags(flags);
cli();
- if ( in_snd[h] != 0 )
- {
- restore_flags(flags);
- return;
+ if (in_snd[h] != 0) {
+ restore_flags(flags);
+ return;
}
- in_snd[h]=1;
- if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0))
- {
- last_cmd[h] &= 0x0f;
- workrequ=curr_req[h][last_cmd[h]];
- goto cmd_subp;
+ in_snd[h] = 1;
+ if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0)) {
+ last_cmd[h] &= 0x0f;
+ workrequ = curr_req[h][last_cmd[h]];
+ goto cmd_subp;
}
workingu[h]++;
- j=quhdu[h];
+ j = quhdu[h];
quhdu[h]++;
- if ( quhdu[h] >= qcnt )
- {
- quhdu[h]=0;
+ if (quhdu[h] >= qcnt) {
+ quhdu[h] = 0;
}
- workrequ=querequ[h][quhdu[h]];
- if ( curr_req[h][workrequ->target] == 0 )
- {
- curr_req[h][workrequ->target]=workrequ;
- last_cmd[h]=workrequ->target;
- goto cmd_subp;
+ workrequ = querequ[h][quhdu[h]];
+ if (curr_req[h][workrequ->target] == 0) {
+ curr_req[h][workrequ->target] = workrequ;
+ last_cmd[h] = workrequ->target;
+ goto cmd_subp;
}
- quhdu[h]=j;
+ quhdu[h] = j;
workingu[h]--;
- in_snd[h]=0;
+ in_snd[h] = 0;
restore_flags(flags);
- return ;
+ return;
cmd_subp:
- workportu=ioportu[h];
- tmport=workportu+0x1f;
- if ((inb(tmport) & 0xb0) != 0)
- {
- goto abortsnd;
- }
- tmport=workportu+0x1c;
- if ( inb(tmport) == 0 )
- {
- goto oktosend;
- }
+ workportu = ioportu[h];
+ tmport = workportu + 0x1f;
+ if ((inb(tmport) & 0xb0) != 0) {
+ goto abortsnd;
+ }
+ tmport = workportu + 0x1c;
+ if (inb(tmport) == 0) {
+ goto oktosend;
+ }
abortsnd:
- last_cmd[h] |= 0x40;
- in_snd[h]=0;
- restore_flags(flags);
- return;
-oktosend:
- memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
- if ( ata_cdbu[h][0] == 0x25 )
- {
- if ( workrequ->request_bufflen > 8 )
- {
- workrequ->request_bufflen=0x08;
- }
- }
- if ( ata_cdbu[h][0] == 0x12 )
- {
- if ( workrequ->request_bufflen > 0x24 )
- {
- workrequ->request_bufflen = 0x24;
- ata_cdbu[h][4]=0x24;
- }
- }
-
- tmport=workportu+0x1b;
- j=inb(tmport) & 0x0e;
- tarid=workrequ->target;
- w=1;
- w = w << tarid;
- if ((w & wide_idu[h]) != 0)
- {
- j |= 0x01;
- }
- outb(j,tmport);
- tmport=workportu;
- outb(workrequ->cmd_len,tmport++);
- outb(0x2c,tmport++);
- outb(0xcf,tmport++);
- for ( i=0 ; i < workrequ->cmd_len ; i++ )
- {
- outb(ata_cdbu[h][i],tmport++);
- }
- tmport=workportu+0x0f;
- outb(0x00,tmport);
- tmport+=0x02;
- outb(devspu[h][tarid],tmport++);
- if (workrequ->use_sg)
- {
-
- l=0;
- sgpnt = (struct scatterlist *) workrequ->request_buffer;
- for(i=0; i<workrequ->use_sg; i++)
- {
- if(sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
- {
- panic("Foooooooood fight!");
- }
- l += sgpnt[i].length;
- }
- }
- else
- {
- l=workrequ->request_bufflen;
- }
- outb((unsigned char)(((unsigned char *)(&l))[2]),tmport++);
- outb((unsigned char)(((unsigned char *)(&l))[1]),tmport++);
- outb((unsigned char)(((unsigned char *)(&l))[0]),tmport++);
- j=tarid;
- last_lenu[h][j]=l;
- tran_lenu[h][j]=0;
- if ((j & 0x08) != 0)
- {
- j=(j & 0x07) | 0x40;
- }
- if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
- (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
- {
- outb((unsigned char)(j | 0x20),tmport++);
- }
- else
- {
- outb(j,tmport++);
- }
- outb(0x80,tmport);
- tmport=workportu + 0x1c;
- dirctu[h][tarid]=0;
- if ( l == 0 )
- {
- if ( inb(tmport) == 0 )
- {
- tmport=workportu+0x18;
- outb(0x08,tmport);
- }
- else
- {
last_cmd[h] |= 0x40;
- }
- in_snd[h]=0;
- restore_flags(flags);
- return;
- }
- tmpcip=pciportu[h];
- prd=&prd_tableu[h][tarid][0];
- prd_posu[h][tarid]=prd;
- if (workrequ->use_sg)
- {
- sgpnt = (struct scatterlist *) workrequ->request_buffer;
- i=0;
- for(j=0; j<workrequ->use_sg; j++)
- {
- (unsigned long)(((unsigned long *)(prd))[i >> 1])=(unsigned long)sgpnt[j].address;
- (unsigned short int)(((unsigned short int *)(prd))[i+2])=sgpnt[j].length;
- (unsigned short int)(((unsigned short int *)(prd))[i+3])=0;
- i +=0x04;
- }
- (unsigned short int)(((unsigned short int *)(prd))[i-1])=0x8000;
- }
- else
- {
- bttl=(unsigned long)workrequ->request_buffer;
- l=workrequ->request_bufflen;
- i=0;
- while ( l > 0x10000 )
- {
- (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x0000;
- (unsigned short int)(((unsigned short int *)(prd))[i+2])=0x0000;
- (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
- l -= 0x10000;
- bttl += 0x10000;
- i += 0x04;
- }
- (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x8000;
- (unsigned short int)(((unsigned short int *)(prd))[i+2])=l;
- (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
- }
- tmpcip=tmpcip+4;
- prdaddru[h][tarid]=(unsigned long)&prd_tableu[h][tarid][0];
- outl(prdaddru[h][tarid],tmpcip);
- tmpcip=tmpcip-2;
- outb(0x06,tmpcip);
- outb(0x00,tmpcip);
- tmpcip=tmpcip-2;
- if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
- (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
- {
- dirctu[h][tarid]=0x20;
- if ( inb(tmport) == 0 )
- {
- tmport=workportu+0x18;
- outb(0x08,tmport);
- outb(0x01,tmpcip);
- }
- else
- {
- last_cmd[h] |= 0x40;
- }
- in_snd[h]=0;
- restore_flags(flags);
- return;
- }
- if ( inb(tmport) == 0 )
- {
- tmport=workportu+0x18;
- outb(0x08,tmport);
- outb(0x09,tmpcip);
- }
- else
- {
- last_cmd[h] |= 0x40;
- }
- in_snd[h]=0;
- restore_flags(flags);
- return;
+ in_snd[h] = 0;
+ restore_flags(flags);
+ return;
+oktosend:
+ memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
+ if (ata_cdbu[h][0] == 0x25) {
+ if (workrequ->request_bufflen > 8) {
+ workrequ->request_bufflen = 0x08;
+ }
+ }
+ if (ata_cdbu[h][0] == 0x12) {
+ if (workrequ->request_bufflen > 0x24) {
+ workrequ->request_bufflen = 0x24;
+ ata_cdbu[h][4] = 0x24;
+ }
+ }
+ tmport = workportu + 0x1b;
+ j = inb(tmport) & 0x0e;
+ tarid = workrequ->target;
+ w = 1;
+ w = w << tarid;
+ if ((w & wide_idu[h]) != 0) {
+ j |= 0x01;
+ }
+ outb(j, tmport);
+ tmport = workportu;
+ outb(workrequ->cmd_len, tmport++);
+ outb(0x2c, tmport++);
+ outb(0xcf, tmport++);
+ for (i = 0; i < workrequ->cmd_len; i++) {
+ outb(ata_cdbu[h][i], tmport++);
+ }
+ tmport = workportu + 0x0f;
+ outb(0x00, tmport);
+ tmport += 0x02;
+ outb(devspu[h][tarid], tmport++);
+ if (workrequ->use_sg)
+ {
+ l = 0;
+ sgpnt = (struct scatterlist *) workrequ->request_buffer;
+ for (i = 0; i < workrequ->use_sg; i++)
+ {
+ if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
+ {
+ panic("Foooooooood fight!");
+ }
+ l += sgpnt[i].length;
+ }
+ } else {
+ l = workrequ->request_bufflen;
+ }
+ outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
+ outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
+ outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+ j = tarid;
+ last_lenu[h][j] = l;
+ tran_lenu[h][j] = 0;
+ if ((j & 0x08) != 0) {
+ j = (j & 0x07) | 0x40;
+ }
+ if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+ (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) {
+ outb((unsigned char) (j | 0x20), tmport++);
+ } else {
+ outb(j, tmport++);
+ }
+ outb(0x80, tmport);
+ tmport = workportu + 0x1c;
+ dirctu[h][tarid] = 0;
+ if (l == 0) {
+ if (inb(tmport) == 0) {
+ tmport = workportu + 0x18;
+ outb(0x08, tmport);
+ } else {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h] = 0;
+ restore_flags(flags);
+ return;
+ }
+ tmpcip = pciportu[h];
+ prd = &prd_tableu[h][tarid][0];
+ prd_posu[h][tarid] = prd;
+ if (workrequ->use_sg)
+ {
+ sgpnt = (struct scatterlist *) workrequ->request_buffer;
+ i = 0;
+ for (j = 0; j < workrequ->use_sg; j++) {
+ (unsigned long) (((unsigned long *) (prd))[i >> 1]) = virt_to_bus(sgpnt[j].address);
+ (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = sgpnt[j].length;
+ (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0;
+ i += 0x04;
+ }
+ (unsigned short int) (((unsigned short int *) (prd))[i - 1]) = 0x8000;
+ } else {
+ bttl = virt_to_bus(workrequ->request_buffer);
+ l = workrequ->request_bufflen;
+ i = 0;
+ while (l > 0x10000) {
+ (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x0000;
+ (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = 0x0000;
+ (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
+ l -= 0x10000;
+ bttl += 0x10000;
+ i += 0x04;
+ }
+ (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x8000;
+ (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = l;
+ (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
+ }
+ tmpcip = tmpcip + 4;
+ prdaddru[h][tarid] = virt_to_bus(&prd_tableu[h][tarid][0]);
+ outl(prdaddru[h][tarid], tmpcip);
+ tmpcip = tmpcip - 2;
+ outb(0x06, tmpcip);
+ outb(0x00, tmpcip);
+ tmpcip = tmpcip - 2;
+ if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+ (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+ {
+ dirctu[h][tarid] = 0x20;
+ if (inb(tmport) == 0) {
+ tmport = workportu + 0x18;
+ outb(0x08, tmport);
+ outb(0x01, tmpcip);
+ } else {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h] = 0;
+ restore_flags(flags);
+ return;
+ }
+ if (inb(tmport) == 0)
+ {
+ tmport = workportu + 0x18;
+ outb(0x08, tmport);
+ outb(0x09, tmpcip);
+ } else {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h] = 0;
+ restore_flags(flags);
+ return;
}
int atp870u_command(Scsi_Cmnd * SCpnt)
{
- atp870u_queuecommand(SCpnt, internal_done);
+ atp870u_queuecommand(SCpnt, internal_done);
- SCpnt->SCp.Status = 0;
- while (!SCpnt->SCp.Status)
- barrier();
- return SCpnt->result;
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier();
+ return SCpnt->result;
}
-unsigned char fun_scam ( unsigned char host,unsigned short int * val )
+unsigned char fun_scam(unsigned char host, unsigned short int *val)
{
- unsigned int tmport ;
- unsigned short int i,k;
- unsigned char j;
+ unsigned int tmport;
+ unsigned short int i, k;
+ unsigned char j;
- tmport = ioportu[host]+0x1c;
- outw(*val,tmport);
+ tmport = ioportu[host] + 0x1c;
+ outw(*val, tmport);
FUN_D7:
- for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
- {
- k=inw(tmport);
- j= (unsigned char)(k >> 8);
- if ((k & 0x8000) != 0) /* DB7 all release? */
- {
- goto FUN_D7;
+ for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
+ k = inw(tmport);
+ j = (unsigned char) (k >> 8);
+ if ((k & 0x8000) != 0) { /* DB7 all release? */
+ goto FUN_D7;
+ }
}
- }
- *val |= 0x4000; /* assert DB6 */
- outw(*val,tmport);
- *val &= 0xdfff; /* assert DB5 */
- outw(*val,tmport);
+ *val |= 0x4000; /* assert DB6 */
+ outw(*val, tmport);
+ *val &= 0xdfff; /* assert DB5 */
+ outw(*val, tmport);
FUN_D5:
- for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
- {
- if ((inw(tmport) & 0x2000) != 0) /* DB5 all release? */
- {
- goto FUN_D5;
- }
- }
- *val |= 0x8000; /* no DB4-0, assert DB7 */
- *val &= 0xe0ff;
- outw(*val,tmport);
- *val &= 0xbfff; /* release DB6 */
- outw(*val,tmport);
-FUN_D6:
- for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
- {
- if ((inw(tmport) & 0x4000) != 0) /* DB6 all release? */
- {
- goto FUN_D6;
- }
- }
-
- return j;
+ for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
+ if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */
+ goto FUN_D5;
+ }
+ }
+ *val |= 0x8000; /* no DB4-0, assert DB7 */
+ *val &= 0xe0ff;
+ outw(*val, tmport);
+ *val &= 0xbfff; /* release DB6 */
+ outw(*val, tmport);
+ FUN_D6:
+ for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
+ if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */
+ goto FUN_D6;
+ }
+ }
+
+ return j;
}
-void tscam( unsigned char host )
+void tscam(unsigned char host)
{
- unsigned int tmport ;
- unsigned char i,j,k;
- unsigned long n;
- unsigned short int m,assignid_map,val;
- unsigned char mbuf[33],quintet[2];
- static unsigned char g2q_tab[8]={ 0x38,0x31,0x32,0x2b,0x34,0x2d,0x2e,0x27 };
+ unsigned int tmport;
+ unsigned char i, j, k;
+ unsigned long n;
+ unsigned short int m, assignid_map, val;
+ unsigned char mbuf[33], quintet[2];
+ static unsigned char g2q_tab[8] =
+ {0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27};
- for ( i=0; i < 0x10; i++ )
- {
- mydlyu(0xffff);
- }
-
- tmport = ioportu[host]+1;
- outb(0x08,tmport++);
- outb(0x7f,tmport);
- tmport = ioportu[host]+0x11;
- outb(0x20,tmport);
-
- if ((scam_on[host] & 0x40) == 0)
- {
- return;
- }
-
- m=1;
- m <<= host_idu[host];
- j=16;
- if ( chip_veru[host] < 4 )
- {
- m |= 0xff00;
- j=8;
- }
- assignid_map=m;
- tmport = ioportu[host]+0x02;
- outb(0x02,tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
- outb(0,tmport++);
- outb(0,tmport++);
- outb(0,tmport++);
- outb(0,tmport++);
- outb(0,tmport++);
- outb(0,tmport++);
-
- for ( i = 0 ; i < j ; i ++ )
- {
- m=1;
- m=m<<i;
- if ( ( m & assignid_map ) != 0 )
- {
- continue;
- }
- tmport = ioportu[host]+0x0f;
- outb(0,tmport++);
- tmport += 0x02;
- outb(0,tmport++);
- outb(0,tmport++);
- outb(0,tmport++);
- if ( i > 7 )
- {
- k=(i & 0x07) | 0x40;
- }
- else
- {
- k=i;
- }
- outb(k,tmport++);
- tmport = ioportu[host]+0x1b;
- if ( chip_veru[host] == 4 )
- {
- outb((unsigned char)((inb(tmport) & 0x0e) | 0x01),tmport);
- }
- else
- {
- outb((unsigned char)(inb(tmport) & 0x0e),tmport);
- }
+ for (i = 0; i < 0x10; i++) {
+ mydlyu(0xffff);
+ }
+
+ tmport = ioportu[host] + 1;
+ outb(0x08, tmport++);
+ outb(0x7f, tmport);
+ tmport = ioportu[host] + 0x11;
+ outb(0x20, tmport);
+
+ if ((scam_on[host] & 0x40) == 0) {
+ return;
+ }
+ m = 1;
+ m <<= host_idu[host];
+ j = 16;
+ if (chip_veru[host] < 4) {
+ m |= 0xff00;
+ j = 8;
+ }
+ assignid_map = m;
+ tmport = ioportu[host] + 0x02;
+ outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+ outb(0, tmport++);
+ outb(0, tmport++);
+ outb(0, tmport++);
+ outb(0, tmport++);
+ outb(0, tmport++);
+ outb(0, tmport++);
+
+ for (i = 0; i < j; i++) {
+ m = 1;
+ m = m << i;
+ if ((m & assignid_map) != 0) {
+ continue;
+ }
+ tmport = ioportu[host] + 0x0f;
+ outb(0, tmport++);
+ tmport += 0x02;
+ outb(0, tmport++);
+ outb(0, tmport++);
+ outb(0, tmport++);
+ if (i > 7) {
+ k = (i & 0x07) | 0x40;
+ } else {
+ k = i;
+ }
+ outb(k, tmport++);
+ tmport = ioportu[host] + 0x1b;
+ if (chip_veru[host] == 4) {
+ outb((unsigned char) ((inb(tmport) & 0x0e) | 0x01), tmport);
+ } else {
+ outb((unsigned char) (inb(tmport) & 0x0e), tmport);
+ }
wait_rdyok:
- tmport = ioportu[host]+0x18;
- outb(0x09,tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00);
- tmport -= 0x08;
- k=inb(tmport);
- if ( k != 0x16 )
- {
- if ((k == 0x85) || (k == 0x42))
- {
- continue;
- }
- tmport = ioportu[host]+0x10;
- outb(0x41,tmport);
- goto wait_rdyok;
- }
- assignid_map |= m;
-
- }
- tmport = ioportu[host]+0x02;
- outb(0x7f,tmport);
- tmport = ioportu[host]+0x1b;
- outb(0x02,tmport);
-
- outb(0,0x80);
-
- val=0x0080; /* bsy */
- tmport = ioportu[host]+0x1c;
- outw(val,tmport);
- val |=0x0040; /* sel */
- outw(val,tmport);
- val |=0x0004; /* msg */
- outw(val,tmport);
- inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
- val &=0x007f; /* no bsy */
- outw(val,tmport);
- mydlyu(0xffff); /* recommanded SCAM selection response time */
- mydlyu(0xffff);
- val &=0x00fb; /* after 1ms no msg */
- outw(val,tmport);
+ tmport = ioportu[host] + 0x18;
+ outb(0x09, tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ k = inb(tmport);
+ if (k != 0x16) {
+ if ((k == 0x85) || (k == 0x42)) {
+ continue;
+ }
+ tmport = ioportu[host] + 0x10;
+ outb(0x41, tmport);
+ goto wait_rdyok;
+ }
+ assignid_map |= m;
+
+ }
+ tmport = ioportu[host] + 0x02;
+ outb(0x7f, tmport);
+ tmport = ioportu[host] + 0x1b;
+ outb(0x02, tmport);
+
+ outb(0, 0x80);
+
+ val = 0x0080; /* bsy */
+ tmport = ioportu[host] + 0x1c;
+ outw(val, tmport);
+ val |= 0x0040; /* sel */
+ outw(val, tmport);
+ val |= 0x0004; /* msg */
+ outw(val, tmport);
+ inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
+ val &= 0x007f; /* no bsy */
+ outw(val, tmport);
+ mydlyu(0xffff); /* recommanded SCAM selection response time */
+ mydlyu(0xffff);
+ val &= 0x00fb; /* after 1ms no msg */
+ outw(val, tmport);
wait_nomsg:
- if ((inb(tmport) & 0x04) != 0)
- {
- goto wait_nomsg;
- }
- outb(1,0x80);
- mydlyu(100);
- for ( n=0; n < 0x30000; n++ )
- {
- if ((inb(tmport) & 0x80) != 0) /* bsy ? */
- {
- goto wait_io;
+ if ((inb(tmport) & 0x04) != 0) {
+ goto wait_nomsg;
+ }
+ outb(1, 0x80);
+ mydlyu(100);
+ for (n = 0; n < 0x30000; n++) {
+ if ((inb(tmport) & 0x80) != 0) { /* bsy ? */
+ goto wait_io;
+ }
}
- }
- goto TCM_SYNC;
+ goto TCM_SYNC;
wait_io:
- for ( n=0; n < 0x30000; n++ )
- {
- if ((inb(tmport) & 0x81) == 0x0081)
- {
- goto wait_io1;
+ for (n = 0; n < 0x30000; n++) {
+ if ((inb(tmport) & 0x81) == 0x0081) {
+ goto wait_io1;
+ }
}
- }
- goto TCM_SYNC;
+ goto TCM_SYNC;
wait_io1:
- inb(0x80);
- val |=0x8003; /* io,cd,db7 */
- outw(val,tmport);
- inb(0x80);
- val &=0x00bf; /* no sel */
- outw(val,tmport);
- outb(2,0x80);
+ inb(0x80);
+ val |= 0x8003; /* io,cd,db7 */
+ outw(val, tmport);
+ inb(0x80);
+ val &= 0x00bf; /* no sel */
+ outw(val, tmport);
+ outb(2, 0x80);
TCM_SYNC:
- mydlyu(0x800);
- if ((inb(tmport) & 0x80) == 0x00) /* bsy ? */
- {
- outw(0,tmport--);
- outb(0,tmport);
- tmport=ioportu[host] + 0x15;
- outb(0,tmport);
- tmport += 0x03;
- outb(0x09,tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0);
- tmport -= 0x08;
- inb(tmport);
- return;
- }
-
- val &= 0x00ff; /* synchronization */
- val |= 0x3f00;
- fun_scam(host,&val);
- outb(3,0x80);
- val &= 0x00ff; /* isolation */
- val |= 0x2000;
- fun_scam(host,&val);
- outb(4,0x80);
- i=8;
- j=0;
+ mydlyu(0x800);
+ if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */
+ outw(0, tmport--);
+ outb(0, tmport);
+ tmport = ioportu[host] + 0x15;
+ outb(0, tmport);
+ tmport += 0x03;
+ outb(0x09, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0);
+ tmport -= 0x08;
+ inb(tmport);
+ return;
+ }
+ val &= 0x00ff; /* synchronization */
+ val |= 0x3f00;
+ fun_scam(host, &val);
+ outb(3, 0x80);
+ val &= 0x00ff; /* isolation */
+ val |= 0x2000;
+ fun_scam(host, &val);
+ outb(4, 0x80);
+ i = 8;
+ j = 0;
TCM_ID:
- if ((inw(tmport) & 0x2000) == 0)
- {
- goto TCM_ID;
- }
- outb(5,0x80);
- val &= 0x00ff; /* get ID_STRING */
- val |= 0x2000;
- k=fun_scam(host,&val);
- if ((k & 0x03) == 0)
- {
- goto TCM_5;
- }
- mbuf[j] <<= 0x01;
- mbuf[j] &= 0xfe;
- if ((k & 0x02) != 0)
- {
- mbuf[j] |= 0x01;
- }
- i--;
- if ( i > 0 )
- {
- goto TCM_ID;
- }
- j++;
- i=8;
- goto TCM_ID;
-
-TCM_5: /* isolation complete.. */
+ if ((inw(tmport) & 0x2000) == 0) {
+ goto TCM_ID;
+ }
+ outb(5, 0x80);
+ val &= 0x00ff; /* get ID_STRING */
+ val |= 0x2000;
+ k = fun_scam(host, &val);
+ if ((k & 0x03) == 0) {
+ goto TCM_5;
+ }
+ mbuf[j] <<= 0x01;
+ mbuf[j] &= 0xfe;
+ if ((k & 0x02) != 0) {
+ mbuf[j] |= 0x01;
+ }
+ i--;
+ if (i > 0) {
+ goto TCM_ID;
+ }
+ j++;
+ i = 8;
+ goto TCM_ID;
+
+TCM_5: /* isolation complete.. */
/* mbuf[32]=0;
- printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
- i=15;
- j=mbuf[0];
- if ((j & 0x20) != 0) /* bit5=1:ID upto 7 */
- {
- i=7;
- }
- if ((j & 0x06) == 0) /* IDvalid? */
- {
- goto G2Q5;
- }
- k=mbuf[1];
+ printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
+ i = 15;
+ j = mbuf[0];
+ if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */
+ i = 7;
+ }
+ if ((j & 0x06) == 0) { /* IDvalid? */
+ goto G2Q5;
+ }
+ k = mbuf[1];
small_id:
- m=1;
- m <<= k;
- if ((m & assignid_map) == 0)
- {
- goto G2Q_QUIN;
- }
- if ( k > 0 )
- {
- k--;
- goto small_id;
- }
-G2Q5: /* srch from max acceptable ID# */
- k=i; /* max acceptable ID# */
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0) {
+ goto G2Q_QUIN;
+ }
+ if (k > 0) {
+ k--;
+ goto small_id;
+ }
+G2Q5: /* srch from max acceptable ID# */
+ k = i; /* max acceptable ID# */
G2Q_LP:
- m=1;
- m <<= k;
- if ((m & assignid_map) == 0)
- {
- goto G2Q_QUIN;
- }
- if ( k > 0 )
- {
- k--;
- goto G2Q_LP;
- }
-G2Q_QUIN: /* k=binID#, */
- assignid_map |= m;
- if ( k < 8 )
- {
- quintet[0]=0x38; /* 1st dft ID<8 */
- }
- else
- {
- quintet[0]=0x31; /* 1st ID>=8 */
- }
- k &= 0x07;
- quintet[1]=g2q_tab[k];
-
- val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */
- m=quintet[0] << 8;
- val |= m;
- fun_scam(host,&val);
- val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */
- m=quintet[1] << 8;
- val |= m;
- fun_scam(host,&val);
-
- goto TCM_SYNC;
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0) {
+ goto G2Q_QUIN;
+ }
+ if (k > 0) {
+ k--;
+ goto G2Q_LP;
+ }
+G2Q_QUIN: /* k=binID#, */
+ assignid_map |= m;
+ if (k < 8) {
+ quintet[0] = 0x38; /* 1st dft ID<8 */
+ } else {
+ quintet[0] = 0x31; /* 1st ID>=8 */
+ }
+ k &= 0x07;
+ quintet[1] = g2q_tab[k];
+
+ val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */
+ m = quintet[0] << 8;
+ val |= m;
+ fun_scam(host, &val);
+ val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */
+ m = quintet[1] << 8;
+ val |= m;
+ fun_scam(host, &val);
+
+ goto TCM_SYNC;
}
-void is870(unsigned long host,unsigned int wkport )
+void is870(unsigned long host, unsigned int wkport)
{
- unsigned int tmport ;
- unsigned char i,j,k,rmb;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0,0,0,0,0,0,0,6,6 };
- static unsigned char inqd[9] = { 0x12,0,0,0,0x24,0,0,0x24,6 };
- static unsigned char synn[6] = { 0x80,1,3,1,0x19,0x0e };
- static unsigned char synu[6] = { 0x80,1,3,1,0x0c,0x0e };
- static unsigned char synw[6] = { 0x80,1,3,1,0x0c,0x07 };
- static unsigned char wide[6] = { 0x80,1,2,3,1,0 };
-
- sync_idu=0;
- tmport=wkport+0x3a;
- outb((unsigned char)(inb(tmport) | 0x10),tmport);
-
- for ( i = 0 ; i < 16 ; i ++ )
- {
- if ((chip_veru[host] != 4) && (i > 7))
- {
- break;
- }
- m=1;
- m=m<<i;
- if ( ( m & active_idu[host] ) != 0 )
- {
- continue;
- }
- if ( i == host_idu[host] )
- {
- printk(" ID: %2d Host Adapter\n",host_idu[host]);
- continue;
- }
- if ( chip_veru[host] == 4 )
- {
- tmport=wkport+0x1b;
- j=(inb(tmport) & 0x0e) | 0x01;
- outb(j,tmport);
- }
- tmport=wkport+1;
- outb(0x08,tmport++);
- outb(0x7f,tmport++);
- outb(satn[0],tmport++);
- outb(satn[1],tmport++);
- outb(satn[2],tmport++);
- outb(satn[3],tmport++);
- outb(satn[4],tmport++);
- outb(satn[5],tmport++);
- tmport+=0x06;
- outb(0,tmport);
- tmport+=0x02;
- outb(devspu[host][i],tmport++);
- outb(0,tmport++);
- outb(satn[6],tmport++);
- outb(satn[7],tmport++);
- j=i;
- if ((j & 0x08) != 0)
- {
- j=(j & 0x07) | 0x40;
- }
- outb(j,tmport);
- tmport+=0x03;
- outb(satn[8],tmport);
- tmport+=0x07;
-
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
- {
- continue;
- }
- while ( inb(tmport) != 0x8e );
- active_idu[host] |= m;
-
- tmport=wkport+0x10;
- outb(0x30,tmport);
- tmport=wkport+0x04;
- outb(0x00,tmport);
+ unsigned int tmport;
+ unsigned char i, j, k, rmb;
+ unsigned short int m;
+ static unsigned char mbuf[512];
+ static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6};
+ static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
+ static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
+ static unsigned char synu[6] = {0x80, 1, 3, 1, 0x0c, 0x0e};
+ static unsigned char synw[6] = {0x80, 1, 3, 1, 0x0c, 0x07};
+ static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0};
+
+ sync_idu = 0;
+ tmport = wkport + 0x3a;
+ outb((unsigned char) (inb(tmport) | 0x10), tmport);
+
+ for (i = 0; i < 16; i++) {
+ if ((chip_veru[host] != 4) && (i > 7)) {
+ break;
+ }
+ m = 1;
+ m = m << i;
+ if ((m & active_idu[host]) != 0) {
+ continue;
+ }
+ if (i == host_idu[host]) {
+ printk(" ID: %2d Host Adapter\n", host_idu[host]);
+ continue;
+ }
+ if (chip_veru[host] == 4) {
+ tmport = wkport + 0x1b;
+ j = (inb(tmport) & 0x0e) | 0x01;
+ outb(j, tmport);
+ }
+ tmport = wkport + 1;
+ outb(0x08, tmport++);
+ outb(0x7f, tmport++);
+ outb(satn[0], tmport++);
+ outb(satn[1], tmport++);
+ outb(satn[2], tmport++);
+ outb(satn[3], tmport++);
+ outb(satn[4], tmport++);
+ outb(satn[5], tmport++);
+ tmport += 0x06;
+ outb(0, tmport);
+ tmport += 0x02;
+ outb(devspu[host][i], tmport++);
+ outb(0, tmport++);
+ outb(satn[6], tmport++);
+ outb(satn[7], tmport++);
+ j = i;
+ if ((j & 0x08) != 0) {
+ j = (j & 0x07) | 0x40;
+ }
+ outb(j, tmport);
+ tmport += 0x03;
+ outb(satn[8], tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+ continue;
+ }
+ while (inb(tmport) != 0x8e);
+ active_idu[host] |= m;
+
+ tmport = wkport + 0x10;
+ outb(0x30, tmport);
+ tmport = wkport + 0x04;
+ outb(0x00, tmport);
phase_cmd:
- tmport=wkport+0x18;
- outb(0x08,tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- j=inb(tmport);
- if ( j != 0x16 )
- {
- tmport=wkport+0x10;
- outb(0x41,tmport);
- goto phase_cmd;
- }
+ tmport = wkport + 0x18;
+ outb(0x08, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ j = inb(tmport);
+ if (j != 0x16) {
+ tmport = wkport + 0x10;
+ outb(0x41, tmport);
+ goto phase_cmd;
+ }
sel_ok:
- tmport=wkport+3;
- outb(inqd[0],tmport++);
- outb(inqd[1],tmport++);
- outb(inqd[2],tmport++);
- outb(inqd[3],tmport++);
- outb(inqd[4],tmport++);
- outb(inqd[5],tmport);
- tmport+=0x07;
- outb(0,tmport);
- tmport+=0x02;
- outb(devspu[host][i],tmport++);
- outb(0,tmport++);
- outb(inqd[6],tmport++);
- outb(inqd[7],tmport++);
- tmport+=0x03;
- outb(inqd[8],tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
- {
- continue;
- }
- while ( inb(tmport) != 0x8e );
- if ( chip_veru[host] == 4 )
- {
- tmport=wkport+0x1b;
- j=inb(tmport) & 0x0e;
- outb(j,tmport);
- }
- tmport=wkport+0x18;
- outb(0x08,tmport);
- tmport += 0x07;
- j=0;
+ tmport = wkport + 3;
+ outb(inqd[0], tmport++);
+ outb(inqd[1], tmport++);
+ outb(inqd[2], tmport++);
+ outb(inqd[3], tmport++);
+ outb(inqd[4], tmport++);
+ outb(inqd[5], tmport);
+ tmport += 0x07;
+ outb(0, tmport);
+ tmport += 0x02;
+ outb(devspu[host][i], tmport++);
+ outb(0, tmport++);
+ outb(inqd[6], tmport++);
+ outb(inqd[7], tmport++);
+ tmport += 0x03;
+ outb(inqd[8], tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+ continue;
+ }
+ while (inb(tmport) != 0x8e);
+ if (chip_veru[host] == 4) {
+ tmport = wkport + 0x1b;
+ j = inb(tmport) & 0x0e;
+ outb(j, tmport);
+ }
+ tmport = wkport + 0x18;
+ outb(0x08, tmport);
+ tmport += 0x07;
+ j = 0;
rd_inq_data:
- k=inb(tmport);
- if ((k & 0x01) != 0 )
- {
- tmport-=0x06;
- mbuf[j++]=inb(tmport);
- tmport+=0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0 )
- {
- goto rd_inq_data;
- }
- tmport-=0x08;
- j=inb(tmport);
- if ( j == 0x16 )
- {
- goto inq_ok;
- }
- tmport=wkport+0x10;
- outb(0x46,tmport);
- tmport+=0x02;
- outb(0,tmport++);
- outb(0,tmport++);
- outb(0,tmport++);
- tmport+=0x03;
- outb(0x08,tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- if (inb(tmport) != 0x16)
- {
- goto sel_ok;
- }
+ k = inb(tmport);
+ if ((k & 0x01) != 0) {
+ tmport -= 0x06;
+ mbuf[j++] = inb(tmport);
+ tmport += 0x06;
+ goto rd_inq_data;
+ }
+ if ((k & 0x80) == 0) {
+ goto rd_inq_data;
+ }
+ tmport -= 0x08;
+ j = inb(tmport);
+ if (j == 0x16) {
+ goto inq_ok;
+ }
+ tmport = wkport + 0x10;
+ outb(0x46, tmport);
+ tmport += 0x02;
+ outb(0, tmport++);
+ outb(0, tmport++);
+ outb(0, tmport++);
+ tmport += 0x03;
+ outb(0x08, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ if (inb(tmport) != 0x16) {
+ goto sel_ok;
+ }
inq_ok:
- mbuf[36]=0;
- printk(" ID: %2d %s\n",i,&mbuf[8]);
- devtypeu[host][i]=mbuf[0];
- rmb=mbuf[1];
- if ( chip_veru[host] != 4 )
- {
- goto not_wide;
- }
- if ((mbuf[7] & 0x60) == 0)
- {
- goto not_wide;
- }
- if ((global_map[host] & 0x20) == 0)
- {
- goto not_wide;
- }
- tmport=wkport+0x1b;
- j=(inb(tmport) & 0x0e) | 0x01;
- outb(j,tmport);
- tmport=wkport+3;
- outb(satn[0],tmport++);
- outb(satn[1],tmport++);
- outb(satn[2],tmport++);
- outb(satn[3],tmport++);
- outb(satn[4],tmport++);
- outb(satn[5],tmport++);
- tmport+=0x06;
- outb(0,tmport);
- tmport+=0x02;
- outb(devspu[host][i],tmport++);
- outb(0,tmport++);
- outb(satn[6],tmport++);
- outb(satn[7],tmport++);
- tmport+=0x03;
- outb(satn[8],tmport);
- tmport+=0x07;
-
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
- {
- continue;
- }
- while ( inb(tmport) != 0x8e );
+ mbuf[36] = 0;
+ printk(" ID: %2d %s\n", i, &mbuf[8]);
+ devtypeu[host][i] = mbuf[0];
+ rmb = mbuf[1];
+ if (chip_veru[host] != 4) {
+ goto not_wide;
+ }
+ if ((mbuf[7] & 0x60) == 0) {
+ goto not_wide;
+ }
+ if ((global_map[host] & 0x20) == 0) {
+ goto not_wide;
+ }
+ tmport = wkport + 0x1b;
+ j = (inb(tmport) & 0x0e) | 0x01;
+ outb(j, tmport);
+ tmport = wkport + 3;
+ outb(satn[0], tmport++);
+ outb(satn[1], tmport++);
+ outb(satn[2], tmport++);
+ outb(satn[3], tmport++);
+ outb(satn[4], tmport++);
+ outb(satn[5], tmport++);
+ tmport += 0x06;
+ outb(0, tmport);
+ tmport += 0x02;
+ outb(devspu[host][i], tmport++);
+ outb(0, tmport++);
+ outb(satn[6], tmport++);
+ outb(satn[7], tmport++);
+ tmport += 0x03;
+ outb(satn[8], tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+ continue;
+ }
+ while (inb(tmport) != 0x8e);
try_wide:
- j=0;
- tmport=wkport+0x14;
- outb(0x05,tmport);
- tmport += 0x04;
- outb(0x20,tmport);
- tmport+=0x07;
-
- while ((inb(tmport) & 0x80) == 0 )
- {
- if ((inb(tmport) & 0x01) != 0 )
- {
- tmport-=0x06;
- outb(wide[j++],tmport);
- tmport+=0x06;
- }
- }
- tmport-=0x08;
- while ((inb(tmport) & 0x80) == 0x00);
- j=inb(tmport) & 0x0f;
- if ( j == 0x0f )
- {
- goto widep_in;
- }
- if ( j == 0x0a )
- {
- goto widep_cmd;
- }
- if ( j == 0x0e )
- {
- goto try_wide;
- }
- continue;
+ j = 0;
+ tmport = wkport + 0x14;
+ outb(0x05, tmport);
+ tmport += 0x04;
+ outb(0x20, tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0) {
+ if ((inb(tmport) & 0x01) != 0) {
+ tmport -= 0x06;
+ outb(wide[j++], tmport);
+ tmport += 0x06;
+ }
+ }
+ tmport -= 0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j = inb(tmport) & 0x0f;
+ if (j == 0x0f) {
+ goto widep_in;
+ }
+ if (j == 0x0a) {
+ goto widep_cmd;
+ }
+ if (j == 0x0e) {
+ goto try_wide;
+ }
+ continue;
widep_out:
- tmport=wkport+0x18;
- outb(0x20,tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0 )
- {
- if ((inb(tmport) & 0x01) != 0 )
- {
- tmport-=0x06;
- outb(0,tmport);
- tmport+=0x06;
- }
- }
- tmport-=0x08;
- j=inb(tmport) & 0x0f;
- if ( j == 0x0f )
- {
- goto widep_in;
- }
- if ( j == 0x0a )
- {
- goto widep_cmd;
- }
- if ( j == 0x0e )
- {
- goto widep_out;
- }
- continue;
+ tmport = wkport + 0x18;
+ outb(0x20, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0) {
+ if ((inb(tmport) & 0x01) != 0) {
+ tmport -= 0x06;
+ outb(0, tmport);
+ tmport += 0x06;
+ }
+ }
+ tmport -= 0x08;
+ j = inb(tmport) & 0x0f;
+ if (j == 0x0f) {
+ goto widep_in;
+ }
+ if (j == 0x0a) {
+ goto widep_cmd;
+ }
+ if (j == 0x0e) {
+ goto widep_out;
+ }
+ continue;
widep_in:
- tmport=wkport+0x14;
- outb(0xff,tmport);
- tmport += 0x04;
- outb(0x20,tmport);
- tmport+=0x07;
- k=0;
+ tmport = wkport + 0x14;
+ outb(0xff, tmport);
+ tmport += 0x04;
+ outb(0x20, tmport);
+ tmport += 0x07;
+ k = 0;
widep_in1:
- j=inb(tmport);
- if ((j & 0x01) != 0)
- {
- tmport-=0x06;
- mbuf[k++]=inb(tmport);
- tmport+=0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00)
- {
- goto widep_in1;
- }
- tmport-=0x08;
- j=inb(tmport) & 0x0f;
- if ( j == 0x0f )
- {
- goto widep_in;
- }
- if ( j == 0x0a )
- {
- goto widep_cmd;
- }
- if ( j == 0x0e )
- {
- goto widep_out;
- }
- continue;
+ j = inb(tmport);
+ if ((j & 0x01) != 0) {
+ tmport -= 0x06;
+ mbuf[k++] = inb(tmport);
+ tmport += 0x06;
+ goto widep_in1;
+ }
+ if ((j & 0x80) == 0x00) {
+ goto widep_in1;
+ }
+ tmport -= 0x08;
+ j = inb(tmport) & 0x0f;
+ if (j == 0x0f) {
+ goto widep_in;
+ }
+ if (j == 0x0a) {
+ goto widep_cmd;
+ }
+ if (j == 0x0e) {
+ goto widep_out;
+ }
+ continue;
widep_cmd:
- tmport=wkport+0x10;
- outb(0x30,tmport);
- tmport=wkport+0x14;
- outb(0x00,tmport);
- tmport+=0x04;
- outb(0x08,tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- j=inb(tmport);
- if ( j != 0x16 )
- {
- if ( j == 0x4e )
- {
- goto widep_out;
- }
- continue;
- }
- if ( mbuf[0] != 0x01 )
- {
- goto not_wide;
- }
- if ( mbuf[1] != 0x02 )
- {
- goto not_wide;
- }
- if ( mbuf[2] != 0x03 )
- {
- goto not_wide;
- }
- if ( mbuf[3] != 0x01 )
- {
- goto not_wide;
- }
- m=1;
- m = m << i;
- wide_idu[host] |= m;
+ tmport = wkport + 0x10;
+ outb(0x30, tmport);
+ tmport = wkport + 0x14;
+ outb(0x00, tmport);
+ tmport += 0x04;
+ outb(0x08, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ j = inb(tmport);
+ if (j != 0x16) {
+ if (j == 0x4e) {
+ goto widep_out;
+ }
+ continue;
+ }
+ if (mbuf[0] != 0x01) {
+ goto not_wide;
+ }
+ if (mbuf[1] != 0x02) {
+ goto not_wide;
+ }
+ if (mbuf[2] != 0x03) {
+ goto not_wide;
+ }
+ if (mbuf[3] != 0x01) {
+ goto not_wide;
+ }
+ m = 1;
+ m = m << i;
+ wide_idu[host] |= m;
not_wide:
- if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07))
- {
- goto set_sync;
- }
- continue;
+ if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07)) {
+ goto set_sync;
+ }
+ continue;
set_sync:
- tmport=wkport+0x1b;
- j=inb(tmport) & 0x0e;
- if ((m & wide_idu[host]) != 0 )
- {
- j |= 0x01;
- }
- outb(j,tmport);
- tmport=wkport+3;
- outb(satn[0],tmport++);
- outb(satn[1],tmport++);
- outb(satn[2],tmport++);
- outb(satn[3],tmport++);
- outb(satn[4],tmport++);
- outb(satn[5],tmport++);
- tmport+=0x06;
- outb(0,tmport);
- tmport+=0x02;
- outb(devspu[host][i],tmport++);
- outb(0,tmport++);
- outb(satn[6],tmport++);
- outb(satn[7],tmport++);
- tmport+=0x03;
- outb(satn[8],tmport);
- tmport+=0x07;
-
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
- {
- continue;
- }
- while ( inb(tmport) != 0x8e);
+ tmport = wkport + 0x1b;
+ j = inb(tmport) & 0x0e;
+ if ((m & wide_idu[host]) != 0) {
+ j |= 0x01;
+ }
+ outb(j, tmport);
+ tmport = wkport + 3;
+ outb(satn[0], tmport++);
+ outb(satn[1], tmport++);
+ outb(satn[2], tmport++);
+ outb(satn[3], tmport++);
+ outb(satn[4], tmport++);
+ outb(satn[5], tmport++);
+ tmport += 0x06;
+ outb(0, tmport);
+ tmport += 0x02;
+ outb(devspu[host][i], tmport++);
+ outb(0, tmport++);
+ outb(satn[6], tmport++);
+ outb(satn[7], tmport++);
+ tmport += 0x03;
+ outb(satn[8], tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+ continue;
+ }
+ while (inb(tmport) != 0x8e);
try_sync:
- j=0;
- tmport=wkport+0x14;
- outb(0x06,tmport);
- tmport += 0x04;
- outb(0x20,tmport);
- tmport+=0x07;
-
- while ((inb(tmport) & 0x80) == 0 )
- {
- if ((inb(tmport) & 0x01) != 0 )
- {
- tmport-=0x06;
- if ( rmb != 0 )
- {
- outb(synn[j++],tmport);
- }
- else
- {
- if ((m & wide_idu[host]) != 0)
- {
- outb(synw[j++],tmport);
- }
- else
- {
- if ((m & ultra_map[host]) != 0)
- {
- outb(synu[j++],tmport);
+ j = 0;
+ tmport = wkport + 0x14;
+ outb(0x06, tmport);
+ tmport += 0x04;
+ outb(0x20, tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0) {
+ if ((inb(tmport) & 0x01) != 0) {
+ tmport -= 0x06;
+ if (rmb != 0) {
+ outb(synn[j++], tmport);
+ } else {
+ if ((m & wide_idu[host]) != 0) {
+ outb(synw[j++], tmport);
+ } else {
+ if ((m & ultra_map[host]) != 0) {
+ outb(synu[j++], tmport);
+ } else {
+ outb(synn[j++], tmport);
+ }
+ }
+ }
+ tmport += 0x06;
+ }
}
- else
- {
- outb(synn[j++],tmport);
- }
- }
- }
- tmport+=0x06;
- }
- }
- tmport-=0x08;
- while ((inb(tmport) & 0x80) == 0x00);
- j=inb(tmport) & 0x0f;
- if ( j == 0x0f )
- {
- goto phase_ins;
- }
- if ( j == 0x0a )
- {
- goto phase_cmds;
- }
- if ( j == 0x0e )
- {
- goto try_sync;
- }
- continue;
+ tmport -= 0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j = inb(tmport) & 0x0f;
+ if (j == 0x0f) {
+ goto phase_ins;
+ }
+ if (j == 0x0a) {
+ goto phase_cmds;
+ }
+ if (j == 0x0e) {
+ goto try_sync;
+ }
+ continue;
phase_outs:
- tmport=wkport+0x18;
- outb(0x20,tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- {
- if ((inb(tmport) & 0x01) != 0x00)
- {
- tmport-=0x06;
- outb(0x00,tmport);
- tmport+=0x06;
- }
- }
- tmport-=0x08;
- j=inb(tmport);
- if ( j == 0x85 )
- {
- goto tar_dcons;
- }
- j &= 0x0f;
- if ( j == 0x0f )
- {
- goto phase_ins;
- }
- if ( j == 0x0a )
- {
- goto phase_cmds;
- }
- if ( j == 0x0e )
- {
- goto phase_outs;
- }
- continue;
+ tmport = wkport + 0x18;
+ outb(0x20, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0x00) {
+ if ((inb(tmport) & 0x01) != 0x00) {
+ tmport -= 0x06;
+ outb(0x00, tmport);
+ tmport += 0x06;
+ }
+ }
+ tmport -= 0x08;
+ j = inb(tmport);
+ if (j == 0x85) {
+ goto tar_dcons;
+ }
+ j &= 0x0f;
+ if (j == 0x0f) {
+ goto phase_ins;
+ }
+ if (j == 0x0a) {
+ goto phase_cmds;
+ }
+ if (j == 0x0e) {
+ goto phase_outs;
+ }
+ continue;
phase_ins:
- tmport=wkport+0x14;
- outb(0xff,tmport);
- tmport += 0x04;
- outb(0x20,tmport);
- tmport+=0x07;
- k=0;
+ tmport = wkport + 0x14;
+ outb(0xff, tmport);
+ tmport += 0x04;
+ outb(0x20, tmport);
+ tmport += 0x07;
+ k = 0;
phase_ins1:
- j=inb(tmport);
- if ((j & 0x01) != 0x00)
- {
- tmport-=0x06;
- mbuf[k++]=inb(tmport);
- tmport+=0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00)
- {
- goto phase_ins1;
- }
- tmport-=0x08;
- while ((inb(tmport) & 0x80) == 0x00);
- j=inb(tmport);
- if ( j == 0x85 )
- {
- goto tar_dcons;
- }
- j &= 0x0f;
- if ( j == 0x0f )
- {
- goto phase_ins;
- }
- if ( j == 0x0a )
- {
- goto phase_cmds;
- }
- if ( j == 0x0e )
- {
- goto phase_outs;
- }
- continue;
+ j = inb(tmport);
+ if ((j & 0x01) != 0x00) {
+ tmport -= 0x06;
+ mbuf[k++] = inb(tmport);
+ tmport += 0x06;
+ goto phase_ins1;
+ }
+ if ((j & 0x80) == 0x00) {
+ goto phase_ins1;
+ }
+ tmport -= 0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j = inb(tmport);
+ if (j == 0x85) {
+ goto tar_dcons;
+ }
+ j &= 0x0f;
+ if (j == 0x0f) {
+ goto phase_ins;
+ }
+ if (j == 0x0a) {
+ goto phase_cmds;
+ }
+ if (j == 0x0e) {
+ goto phase_outs;
+ }
+ continue;
phase_cmds:
- tmport=wkport+0x10;
- outb(0x30,tmport);
+ tmport = wkport + 0x10;
+ outb(0x30, tmport);
tar_dcons:
- tmport=wkport+0x14;
- outb(0x00,tmport);
- tmport+=0x04;
- outb(0x08,tmport);
- tmport+=0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport-=0x08;
- j=inb(tmport);
- if ( j != 0x16 )
- {
- continue;
- }
- if ( mbuf[0] != 0x01 )
- {
- continue;
- }
- if ( mbuf[1] != 0x03 )
- {
- continue;
- }
- if ( mbuf[4] == 0x00 )
- {
- continue;
- }
- if ( mbuf[3] > 0x64 )
- {
- continue;
- }
- if ( mbuf[4] > 0x0c )
- {
- mbuf[4]=0x0c;
- }
- devspu[host][i] = mbuf[4];
- if ((mbuf[3] < 0x0d) && (rmb == 0))
- {
- j=0xa0;
- goto set_syn_ok;
- }
- if ( mbuf[3] < 0x1a )
- {
- j=0x20;
- goto set_syn_ok;
- }
- if ( mbuf[3] < 0x33 )
- {
- j=0x40;
- goto set_syn_ok;
- }
- if ( mbuf[3] < 0x4c )
- {
- j=0x50;
- goto set_syn_ok;
- }
- j=0x60;
-set_syn_ok:
- devspu[host][i] = (devspu[host][i] & 0x0f) | j;
- }
- tmport=wkport+0x3a;
- outb((unsigned char)(inb(tmport) & 0xef),tmport);
+ tmport = wkport + 0x14;
+ outb(0x00, tmport);
+ tmport += 0x04;
+ outb(0x08, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ j = inb(tmport);
+ if (j != 0x16) {
+ continue;
+ }
+ if (mbuf[0] != 0x01) {
+ continue;
+ }
+ if (mbuf[1] != 0x03) {
+ continue;
+ }
+ if (mbuf[4] == 0x00) {
+ continue;
+ }
+ if (mbuf[3] > 0x64) {
+ continue;
+ }
+ if (mbuf[4] > 0x0c) {
+ mbuf[4] = 0x0c;
+ }
+ devspu[host][i] = mbuf[4];
+ if ((mbuf[3] < 0x0d) && (rmb == 0)) {
+ j = 0xa0;
+ goto set_syn_ok;
+ }
+ if (mbuf[3] < 0x1a) {
+ j = 0x20;
+ goto set_syn_ok;
+ }
+ if (mbuf[3] < 0x33) {
+ j = 0x40;
+ goto set_syn_ok;
+ }
+ if (mbuf[3] < 0x4c) {
+ j = 0x50;
+ goto set_syn_ok;
+ }
+ j = 0x60;
+ set_syn_ok:
+ devspu[host][i] = (devspu[host][i] & 0x0f) | j;
+ }
+ tmport = wkport + 0x3a;
+ outb((unsigned char) (inb(tmport) & 0xef), tmport);
}
/* return non-zero on detection */
int atp870u_detect(Scsi_Host_Template * tpnt)
{
- unsigned char irq,h,k;
- unsigned long flags;
- unsigned int base_io,error,tmport;
- unsigned short index = 0;
- unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3],host_id;
- struct Scsi_Host * shpnt = NULL;
- int count = 0;
- static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0};
- static struct pci_dev *pdev = NULL, *acard_pdev[3];
-
- printk("aec671x_detect: \n");
- if (!pci_present())
- {
- printk(" NO BIOS32 SUPPORT.\n");
- return count;
- }
-
- tpnt->proc_dir = &proc_scsi_atp870u;
-
- for ( h = 0 ; h < 2 ; h++ )
- {
- active_idu[h]=0;
- wide_idu[h]=0;
- host_idu[h]=0x07;
- quhdu[h]=0;
- quendu[h]=0;
- pci_bus[h]=0;
- pci_device_fn[h]=0xff;
- chip_ver[h]=0;
- last_cmd[h]=0xff;
- in_snd[h]=0;
- in_int[h]=0;
- for ( k = 0 ; k < qcnt ; k++ )
- {
- querequ[h][k]=0;
- }
- for ( k = 0 ; k < 16 ; k++ )
- {
- curr_req[h][k]=0;
- }
- }
- h=0;
- while ( devid[h] != 0 )
- {
- pdev = pci_find_device(0x1191,devid[h],pdev);
- if (pdev == NULL) {
- h++;
- index=0;
- continue;
- }
- chip_ver[2]=0;
-
- /* To avoid messing with the things below... */
- acard_pdev[2] = pdev;
- pci_device_fn[2] = pdev->devfn;
- pci_bus[2] = pdev->bus->number;
-
- if ( devid[h] == 0x8002 )
- {
- error = pci_read_config_byte(pdev,0x08,&chip_ver[2]);
- if ( chip_ver[2] < 2 )
- {
- goto nxt_devfn;
- }
- }
- if ( devid[h] == 0x8010 )
- {
- chip_ver[2]=0x04;
- }
- if ( pci_device_fn[2] < pci_device_fn[0] )
- {
- acard_pdev[1]=acard_pdev[0];
- pci_bus[1]=pci_bus[0];
- pci_device_fn[1]=pci_device_fn[0];
- chip_ver[1]=chip_ver[0];
- acard_pdev[0]=acard_pdev[2];
- pci_bus[0]=pci_bus[2];
- pci_device_fn[0]=pci_device_fn[2];
- chip_ver[0]=chip_ver[2];
- }
- else if ( pci_device_fn[2] < pci_device_fn[1] )
- {
- acard_pdev[1]=acard_pdev[2];
- pci_bus[1]=pci_bus[2];
- pci_device_fn[1]=pci_device_fn[2];
- chip_ver[1]=chip_ver[2];
- }
-nxt_devfn:
- index++;
- if ( index > 3 )
- {
- index=0;
- h++;
- }
- }
- for ( h=0; h < 2; h++ )
- {
- if ( pci_device_fn[h] == 0xff )
- {
- return count;
- }
-
- pdev = acard_pdev[h];
- pdev->devfn = pci_device_fn[h];
- pdev->bus->number = pci_bus[h];
-
- /* Found an atp870u/w. */
- error = pci_read_config_dword(pdev,0x10,&base_io);
- error += pci_read_config_byte(pdev,0x3c,&irq);
- error += pci_read_config_byte(pdev,0x49,&host_id);
-
- base_io &= 0xfffffff8;
- printk(" ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n"
- ,h,base_io,irq);
- ioportu[h]=base_io;
- pciportu[h]=base_io + 0x20;
- irqnumu[h]=irq;
- host_id &= 0x07;
- host_idu[h]=host_id;
- chip_veru[h]=chip_ver[h];
-
- tmport=base_io+0x22;
- scam_on[h]=inb(tmport);
- tmport += 0x0b;
- global_map[h]=inb(tmport++);
- ultra_map[h]=inw(tmport);
- if ( ultra_map[h] == 0 )
- {
- scam_on[h]=0x00;
- global_map[h]=0x20;
- ultra_map[h]=0xffff;
- }
-
- shpnt = scsi_register(tpnt,4);
-
- save_flags(flags);
- cli();
- if (request_irq(irq,atp870u_intr_handle, 0, "atp870u", NULL))
- {
- printk("Unable to allocate IRQ for Acard controller.\n");
- goto unregister;
- }
-
- tmport=base_io+0x3a;
- k=(inb(tmport) & 0xf3) | 0x10;
- outb(k,tmport);
- outb((k & 0xdf),tmport);
- mydlyu(0x8000);
- outb(k,tmport);
- mydlyu(0x8000);
- tmport=base_io;
- outb((host_id | 0x08),tmport);
- tmport += 0x18;
- outb(0,tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0);
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io +1;
- outb(8,tmport++);
- outb(0x7f,tmport);
- tmport = base_io + 0x11;
- outb(0x20,tmport);
-
- tscam(h);
- is870(h,base_io);
- tmport=base_io+0x3a;
- outb((inb(tmport) & 0xef),tmport);
-
- atp_host[h] = shpnt;
- if ( chip_ver[h] == 4 )
- {
- shpnt->max_id = 16;
- }
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */
- shpnt->irq = irq;
- restore_flags(flags);
- request_region(base_io, 0x40,"atp870u"); /* Register the IO ports that we use */
- count++;
- index++;
- continue;
+ unsigned char irq, h, k;
+ unsigned long flags;
+ unsigned int base_io, error, tmport;
+ unsigned short index = 0;
+ unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3], host_id;
+ struct Scsi_Host *shpnt = NULL;
+ int count = 0;
+ static unsigned short devid[7] =
+ {0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0};
+ static struct pci_dev *pdev = NULL, *acard_pdev[3];
+
+ printk("aec671x_detect: \n");
+ if (!pci_present()) {
+ printk(" NO BIOS32 SUPPORT.\n");
+ return count;
+ }
+ tpnt->proc_dir = &proc_scsi_atp870u;
+
+ for (h = 0; h < 2; h++) {
+ active_idu[h] = 0;
+ wide_idu[h] = 0;
+ host_idu[h] = 0x07;
+ quhdu[h] = 0;
+ quendu[h] = 0;
+ pci_bus[h] = 0;
+ pci_device_fn[h] = 0xff;
+ chip_ver[h] = 0;
+ last_cmd[h] = 0xff;
+ in_snd[h] = 0;
+ in_int[h] = 0;
+ for (k = 0; k < qcnt; k++) {
+ querequ[h][k] = 0;
+ }
+ for (k = 0; k < 16; k++) {
+ curr_req[h][k] = 0;
+ }
+ }
+ h = 0;
+ while (devid[h] != 0) {
+ pdev = pci_find_device(0x1191, devid[h], pdev);
+ if (pdev == NULL) {
+ h++;
+ index = 0;
+ continue;
+ }
+ chip_ver[2] = 0;
+
+ /* To avoid messing with the things below... */
+ acard_pdev[2] = pdev;
+ pci_device_fn[2] = pdev->devfn;
+ pci_bus[2] = pdev->bus->number;
+
+ if (devid[h] == 0x8002) {
+ error = pci_read_config_byte(pdev, 0x08, &chip_ver[2]);
+ if (chip_ver[2] < 2) {
+ goto nxt_devfn;
+ }
+ }
+ if (devid[h] == 0x8010) {
+ chip_ver[2] = 0x04;
+ }
+ if (pci_device_fn[2] < pci_device_fn[0]) {
+ acard_pdev[1] = acard_pdev[0];
+ pci_bus[1] = pci_bus[0];
+ pci_device_fn[1] = pci_device_fn[0];
+ chip_ver[1] = chip_ver[0];
+ acard_pdev[0] = acard_pdev[2];
+ pci_bus[0] = pci_bus[2];
+ pci_device_fn[0] = pci_device_fn[2];
+ chip_ver[0] = chip_ver[2];
+ } else if (pci_device_fn[2] < pci_device_fn[1]) {
+ acard_pdev[1] = acard_pdev[2];
+ pci_bus[1] = pci_bus[2];
+ pci_device_fn[1] = pci_device_fn[2];
+ chip_ver[1] = chip_ver[2];
+ }
+ nxt_devfn:
+ index++;
+ if (index > 3) {
+ index = 0;
+ h++;
+ }
+ }
+ for (h = 0; h < 2; h++) {
+ if (pci_device_fn[h] == 0xff) {
+ return count;
+ }
+ pdev = acard_pdev[h];
+ pdev->devfn = pci_device_fn[h];
+ pdev->bus->number = pci_bus[h];
+
+ /* Found an atp870u/w. */
+ error = pci_read_config_dword(pdev, 0x10, &base_io);
+ error += pci_read_config_byte(pdev, 0x3c, &irq);
+ error += pci_read_config_byte(pdev, 0x49, &host_id);
+
+ base_io &= 0xfffffff8;
+ printk(" ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n"
+ ,h, base_io, irq);
+ ioportu[h] = base_io;
+ pciportu[h] = base_io + 0x20;
+ irqnumu[h] = irq;
+ host_id &= 0x07;
+ host_idu[h] = host_id;
+ chip_veru[h] = chip_ver[h];
+
+ tmport = base_io + 0x22;
+ scam_on[h] = inb(tmport);
+ tmport += 0x0b;
+ global_map[h] = inb(tmport++);
+ ultra_map[h] = inw(tmport);
+ if (ultra_map[h] == 0) {
+ scam_on[h] = 0x00;
+ global_map[h] = 0x20;
+ ultra_map[h] = 0xffff;
+ }
+ shpnt = scsi_register(tpnt, 4);
+
+ save_flags(flags);
+ cli();
+ if (request_irq(irq, atp870u_intr_handle, 0, "atp870u", NULL)) {
+ printk("Unable to allocate IRQ for Acard controller.\n");
+ goto unregister;
+ }
+ tmport = base_io + 0x3a;
+ k = (inb(tmport) & 0xf3) | 0x10;
+ outb(k, tmport);
+ outb((k & 0xdf), tmport);
+ mydlyu(0x8000);
+ outb(k, tmport);
+ mydlyu(0x8000);
+ tmport = base_io;
+ outb((host_id | 0x08), tmport);
+ tmport += 0x18;
+ outb(0, tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0);
+ tmport -= 0x08;
+ inb(tmport);
+ tmport = base_io + 1;
+ outb(8, tmport++);
+ outb(0x7f, tmport);
+ tmport = base_io + 0x11;
+ outb(0x20, tmport);
+
+ tscam(h);
+ is870(h, base_io);
+ tmport = base_io + 0x3a;
+ outb((inb(tmport) & 0xef), tmport);
+
+ atp_host[h] = shpnt;
+ if (chip_ver[h] == 4) {
+ shpnt->max_id = 16;
+ }
+ shpnt->this_id = host_id;
+ shpnt->unique_id = base_io;
+ shpnt->io_port = base_io;
+ shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */
+ shpnt->irq = irq;
+ restore_flags(flags);
+ request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */
+ count++;
+ index++;
+ continue;
unregister:
- scsi_unregister(shpnt);
- restore_flags(flags);
- index++;
- continue;
- }
+ scsi_unregister(shpnt);
+ restore_flags(flags);
+ index++;
+ continue;
+ }
- return count;
+ return count;
}
/* The abort command does not leave the device in a clean state where
int atp870u_abort(Scsi_Cmnd * SCpnt)
{
- unsigned char h,j;
- unsigned int tmport;
+ unsigned char h, j;
+ unsigned int tmport;
/* printk(" atp870u_abort: \n"); */
- for ( h=0; h <= admaxu; h++ )
- {
- if ( SCpnt->host == atp_host[h] )
- {
- goto find_adp;
+ for (h = 0; h <= admaxu; h++) {
+ if (SCpnt->host == atp_host[h]) {
+ goto find_adp;
+ }
}
- }
- panic("Abort host not found !");
+ panic("Abort host not found !");
find_adp:
- printk(" workingu=%x last_cmd=%x ",workingu[h],last_cmd[h]);
- printk(" quhdu=%x quendu=%x ",quhdu[h],quendu[h]);
- tmport=ioportu[h];
- for ( j=0; j < 0x17; j++)
- {
- printk(" r%2x=%2x",j,inb(tmport++));
- }
- tmport += 0x05;
- printk(" r1c=%2x",inb(tmport));
- tmport += 0x03;
- printk(" r1f=%2x in_snd=%2x ",inb(tmport),in_snd[h]);
- tmport++;
- printk(" r20=%2x",inb(tmport));
- tmport += 0x02;
- printk(" r22=%2x \n",inb(tmport));
- return (SCSI_ABORT_SNOOZE);
+ printk(" workingu=%x last_cmd=%x ", workingu[h], last_cmd[h]);
+ printk(" quhdu=%x quendu=%x ", quhdu[h], quendu[h]);
+ tmport = ioportu[h];
+ for (j = 0; j < 0x17; j++) {
+ printk(" r%2x=%2x", j, inb(tmport++));
+ }
+ tmport += 0x05;
+ printk(" r1c=%2x", inb(tmport));
+ tmport += 0x03;
+ printk(" r1f=%2x in_snd=%2x ", inb(tmport), in_snd[h]);
+ tmport++;
+ printk(" r20=%2x", inb(tmport));
+ tmport += 0x02;
+ printk(" r22=%2x \n", inb(tmport));
+ return (SCSI_ABORT_SNOOZE);
}
int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
{
- unsigned char h;
- /*
- * See if a bus reset was suggested.
- */
-/* printk("atp870u_reset: \n"); */
- for( h=0; h <= admaxu; h++ )
- {
- if ( SCpnt->host == atp_host[h] )
- {
- goto find_host;
- }
- }
- panic("Reset bus host not found !");
+ unsigned char h;
+ /*
+ * See if a bus reset was suggested.
+ */
+/* printk("atp870u_reset: \n"); */
+ for (h = 0; h <= admaxu; h++) {
+ if (SCpnt->host == atp_host[h]) {
+ goto find_host;
+ }
+ }
+ panic("Reset bus host not found !");
find_host:
-/* SCpnt->result = 0x00080000;
- SCpnt->scsi_done(SCpnt);
- workingu[h]=0;
- quhdu[h]=0;
- quendu[h]=0;
- return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); */
- return (SCSI_RESET_SNOOZE);
+/* SCpnt->result = 0x00080000;
+ SCpnt->scsi_done(SCpnt);
+ workingu[h]=0;
+ quhdu[h]=0;
+ quendu[h]=0;
+ return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); */
+ return (SCSI_RESET_SNOOZE);
}
-const char *
-atp870u_info(struct Scsi_Host *notused)
+const char *atp870u_info(struct Scsi_Host *notused)
{
- static char buffer[128];
+ static char buffer[128];
- strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
+ strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
- return buffer;
+ return buffer;
}
-int
-atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
{
- return (-ENOSYS); /* Currently this is a no-op */
+ return (-ENOSYS); /* Currently this is a no-op */
}
#define BLS buffer + len + size
-int
-atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout)
+int atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
{
- struct Scsi_Host *HBAptr;
- static u8 buff[512];
- int i;
- int size = 0;
- int len = 0;
- off_t begin = 0;
- off_t pos = 0;
-
- HBAptr = NULL;
- for (i = 0; i < 2; i++)
- {
- if ((HBAptr = atp_host[i]) != NULL)
- {
- if (HBAptr->host_no == hostno)
- {
- break;
- }
- HBAptr = NULL;
- }
- }
-
- if (HBAptr == NULL)
- {
- size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
- len += size; pos = begin + len; size = 0;
- goto stop_output;
- }
-
- if (inout == TRUE) /* Has data been written to the file? */
- {
- return (atp870u_set_info(buffer, length, HBAptr));
- }
-
- if (offset == 0)
- {
- memset(buff, 0, sizeof(buff));
- }
-
- size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
- len += size; pos = begin + len; size = 0;
-
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Adapter Configuration:\n");
- size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port);
- size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
- len += size; pos = begin + len; size = 0;
-
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- {
- len = length; /* Ending slop */
- }
-
- return (len);
+ struct Scsi_Host *HBAptr;
+ static u8 buff[512];
+ int i;
+ int size = 0;
+ int len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ HBAptr = NULL;
+ for (i = 0; i < 2; i++) {
+ if ((HBAptr = atp_host[i]) != NULL) {
+ if (HBAptr->host_no == hostno) {
+ break;
+ }
+ HBAptr = NULL;
+ }
+ }
+
+ if (HBAptr == NULL) {
+ size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
+ len += size;
+ pos = begin + len;
+ size = 0;
+ goto stop_output;
+ }
+ if (inout == TRUE) { /* Has data been written to the file? */
+ return (atp870u_set_info(buffer, length, HBAptr));
+ }
+ if (offset == 0) {
+ memset(buff, 0, sizeof(buff));
+ }
+ size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
+ len += size;
+ pos = begin + len;
+ size = 0;
+
+ size += sprintf(BLS, "\n");
+ size += sprintf(BLS, "Adapter Configuration:\n");
+ size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port);
+ size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
+ len += size;
+ pos = begin + len;
+ size = 0;
+
+ stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length) {
+ len = length; /* Ending slop */
+ }
+ return (len);
}
#include "sd.h"
-int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip)
+int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
{
- int heads, sectors, cylinders;
+ int heads, sectors, cylinders;
- heads = 64;
- sectors = 32;
- cylinders = disk->capacity / (heads * sectors);
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
- if ( cylinders > 1024 )
- {
- heads = 255;
- sectors = 63;
- cylinders = disk->capacity / (heads * sectors);
- }
-
- ip[0] = heads;
- ip[1] = sectors;
- ip[2] = cylinders;
+ if (cylinders > 1024) {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (heads * sectors);
+ }
+ ip[0] = heads;
+ ip[1] = sectors;
+ ip[2] = cylinders;
- return 0;
+ return 0;
}
#ifdef MODULE
#include "scsi_module.c"
#endif
-
#ifndef _ATP870U_H
/* $Id: atp870u.h,v 1.0 1997/05/07 15:09:00 root Exp root $
- *
+
* Header file for the ACARD 870U/W driver for Linux
*
* $Log: atp870u.h,v $
int atp870u_detect(Scsi_Host_Template *);
int atp870u_command(Scsi_Cmnd *);
-int atp870u_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int atp870u_abort(Scsi_Cmnd *);
int atp870u_reset(Scsi_Cmnd *, unsigned int);
-int atp870u_biosparam(Disk *, kdev_t, int*);
+int atp870u_biosparam(Disk *, kdev_t, int *);
void send_s870(unsigned char);
#define qcnt 32
#define ATP870U_CMDLUN 1
#ifndef NULL
- #define NULL 0
+#define NULL 0
#endif
extern struct proc_dir_entry proc_scsi_atp870u;
scsi->pc = NULL;
}
-static inline unsigned long get_timeout(idescsi_pc_t *pc)
-{
- return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
-}
-
/*
* Our interrupt handler.
*/
pc->actually_transferred += temp;
pc->current_position += temp;
idescsi_discard_data (drive,bcount - temp);
- ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));
+ drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+ ide_set_handler(drive, &idescsi_pc_intr);
return;
}
#if IDESCSI_DEBUG_LOG
pc->actually_transferred+=bcount; /* Update the current position */
pc->current_position+=bcount;
- ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* And set the interrupt handler again */
+ drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+ ide_set_handler(drive, &idescsi_pc_intr); /* And set the interrupt handler again */
}
static void idescsi_transfer_pc (ide_drive_t *drive)
ide_do_reset (drive);
return;
}
- ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* Set the interrupt routine */
+ drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+ ide_set_handler(drive, &idescsi_pc_intr); /* Set the interrupt routine */
atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */
}
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
}
if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
- ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc));
+ drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+ ide_set_handler (drive, &idescsi_transfer_pc);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
/*
* drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
*/
- ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL);
#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */
/* Status of ORCSCB_Status */
-#define SCB_COMPLETE 0x00 /* SCB request completed */
-#define SCB_POST 0x01 /* SCB is posted by the HOST */
+#define ORCSCB_COMPLETE 0x00 /* SCB request completed */
+#define ORCSCB_POST 0x01 /* SCB is posted by the HOST */
/* Bit Definition for ORCSCB_Flags */
#define SCF_DISINT 0x01 /* Disable HOST interrupt */
}
if ((scb->scsi_cmd->request.cmd == READ) && (SC->request_bufflen))
- scb->dcdb.cmd_attribute |= DATA_IN;
+ scb->dcdb.cmd_attribute |= IPS_DATA_IN;
if ((scb->scsi_cmd->request.cmd == WRITE) && (SC->request_bufflen))
- scb->dcdb.cmd_attribute |= DATA_OUT;
+ scb->dcdb.cmd_attribute |= IPS_DATA_OUT;
if (scb->data_len >= IPS_MAX_XFER) {
scb->dcdb.cmd_attribute |= TRANSFER_64K;
}
if ((scb->scsi_cmd->request.cmd == READ) && (scb->data_len))
- scb->dcdb.cmd_attribute |= DATA_IN;
+ scb->dcdb.cmd_attribute |= IPS_DATA_IN;
if ((scb->scsi_cmd->request.cmd == WRITE) && (scb->data_len))
- scb->dcdb.cmd_attribute |= DATA_OUT;
+ scb->dcdb.cmd_attribute |= IPS_DATA_OUT;
if (scb->data_len >= IPS_MAX_XFER) {
scb->dcdb.cmd_attribute |= TRANSFER_64K;
#define NO_DISCONNECT 0x00
#define DISCONNECT_ALLOWED 0x80
#define NO_AUTO_REQUEST_SENSE 0x40
- #define DATA_IN 0x01
- #define DATA_OUT 0x02
+ #define IPS_DATA_IN 0x01
+ #define IPS_DATA_OUT 0x02
#define TRANSFER_64K 0x08
#define NOTIMEOUT 0x00
#define TIMEOUT10 0x10
#define U14_34F_VERSION "5.11.00"
+#ifndef LinuxVersionCode
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
#define ULTRASTOR_14_34F { \
name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
__maestro_write(ess->card,reg,data);
- spin_unlock_irqrestore(&card->lock,flags);
+ spin_unlock_irqrestore(&ess->card->lock,flags);
}
static u16 __maestro_read(struct ess_card *card, u16 reg)
#ifdef CONFIG_SOUND_MSNDPIN
extern int msnd_pinnacle_init(void);
#endif
+#ifdef CONFIG_SOUND_CMPCI
+extern init_cmpci(void);
+#endif
/*
* Low level list operator. Scan the ordered list, find a hole and
int i;
int y, u, y1, v, r, g, b;
- /* We want atleast 2 bytes for the length */
+ /* We want at least 2 bytes for the length */
if (scratch_left(data) < 2)
goto out;
return totlen;
}
-static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
+static int cpia_isoc_irq(int status, void *__buffer, int len, void *isocdesc)
{
+ void *dev_id = ((struct usb_isoc_desc *)isocdesc)->context;
struct usb_cpia *cpia = (struct usb_cpia *)dev_id;
struct cpia_sbuf *sbuf;
int i;
cpia->cursbuf = 0;
cpia->scratchlen = 0;
+ /* Alternate interface 3 is is the biggest frame size */
+ if (usb_set_interface(cpia->dev, 1, 3) < 0) {
+ printk("usb_set_interface error\n");
+ return -EBUSY;
+ }
+
/* We double buffer the Iso lists */
err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
cpia, &cpia->sbuf[0].isodesc);
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
- /* and the desc. [1] */
+ /* and for desc. [1] */
id = cpia->sbuf[1].isodesc;
id->start_type = 0; /* will follow the first desc. */
id->callback_frames = 10; /* on every 10th frame */
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
- usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
- usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
+ err = usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
+ if (err)
+ printk(KERN_ERR "CPiA USB driver error (%d) on usb_run_isoc\n", err);
+ err = usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
+ if (err)
+ printk(KERN_ERR "CPiA USB driver error (%d) on usb_run_isoc\n", err);
#ifdef CPIA_DEBUG
printk("done scheduling\n");
#endif
- /* Alternate interface 3 is is the biggest frame size */
- if (usb_set_interface(cpia->dev, 1, 3) < 0) {
- printk("usb_set_interface error\n");
- return -EBUSY;
- }
#if 0
if (usb_cpia_grab_frame(dev, 120) < 0) {
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;
+ p.palette = VIDEO_PALETTE_RGB24;
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
#ifdef CPIA_DEBUG
printk("Attempting to set palette %d, depth %d\n",
p.palette, p.depth);
+ printk("SPICT: brightness=%d, hue=%d, colour=%d, contrast=%d, whiteness=%d\n",
+ p.brightness, p.hue, p.colour, p.contrast, p.whiteness);
#endif
return 0;
{
struct video_mmap vm;
-
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
return cpia_new_frame(cpia, -1);
}
+ case VIDIOCGFBUF:
+ {
+ struct video_buffer vb;
+
+#ifdef CPIA_DEBUG
+ printk("GFBUF\n");
+#endif
+
+ memset(&vb, 0, sizeof(vb));
+ vb.base = NULL; /* frame buffer not supported, not used */
+
+ if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+ return -EFAULT;
+
+ return 0;
+ }
case VIDIOCKEY:
return 0;
case VIDIOCCAPTURE:
return -EINVAL;
- case VIDIOCGFBUF:
case VIDIOCSFBUF:
return -EINVAL;
case VIDIOCGTUNER:
usb_cpia_cleanup();
}
#endif
-
if (partial) {
count = this_read = partial;
- } else if (result == USB_ST_TIMEOUT || result == 15) {
+ } else if (result == USB_ST_TIMEOUT || result == 15) { /* FIXME: 15 ??? */
if(!maxretry--) {
printk(KERN_DEBUG "read_scanner: maxretry timeout\n");
return -ETIME;
-int usb_kbd_init(void);
+int usb_acm_init(void);
int usb_audio_init(void);
int usb_hub_init(void);
-int usb_acm_init(void);
-int usb_printer_init(void);
void usb_hub_cleanup(void);
+int usb_kbd_init(void);
+void usb_major_init(void);
void usb_mouse_cleanup(void);
-int usb_scsi_init(void);
int usb_hp_scanner_init(void);
void usb_hp_scanner_cleanup(void);
+int usb_printer_init(void);
int proc_usb_init (void);
void proc_usb_cleanup (void);
+int usb_scsi_init(void);
int usb_serial_init (void);
/*
* Map status to standard result codes
*
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
* <dir_out> is True for output TDs and False for input TDs.
*/
static int uhci_map_status(int status, int dir_out)
do {
status = uhci_status_bits(tmp->status);
- if (status)
- break;
-#if 0
- if (debug) {
+ if (status) {
+ if (debug) {
/* Must reset the toggle on first error */
- if (uhci_debug) {
+ if (uhci_debug)
printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
(unsigned int)tmp, rval ? *rval : 0);
- }
usb_settoggle(dev->usb, uhci_endpoint(tmp->info),
uhci_packetout(tmp->info) ^ 1,
uhci_toggle(tmp->info));
break;
}
- } else {
- if (rval && ((tmp->info & 0xFF) == USB_PID_IN))
- *rval += uhci_actual_length(tmp->status);
}
-#endif
+
/* The length field is only valid if the TD was completed */
+ if (!status)
if (!(tmp->status & TD_CTRL_ACTIVE) && uhci_packetin(tmp->info)) {
bytesreceived += uhci_actual_length(tmp->status);
if (rval)
if (!status)
return USB_ST_NOERROR;
- /* XXX FIXME APC BackUPS Pro kludge */
+ /* APC BackUPS Pro kludge */
/* It tries to send all of the descriptor instead of */
/* the amount we requested */
if (tmp->status & TD_CTRL_IOC &&
tmp->status & TD_CTRL_ACTIVE &&
- tmp->status & TD_CTRL_NAK /* && its a control TD */)
+ tmp->status & TD_CTRL_NAK &&
+ tmp->pipetype == PIPE_CONTROL)
return USB_ST_NOERROR;
#if 0
/* If this wasn't the last TD and SPD is set, ACTIVE */
/* is not and NAK isn't then we received a short */
/* packet */
- if (tmp->status & TD_CTRL_SPD &&
- !(tmp->status & TD_CTRL_NAK))
+ if (tmp->status & TD_CTRL_SPD && !(tmp->status & TD_CTRL_NAK))
return USB_ST_NOERROR;
}
* bit set. Maybe it could be extended to handle the QH's also,
* but it doesn't seem necessary right now.
* The layout looks as follows:
- * frame list pointer -> iso td's (if any) ->
+ * frame list pointer -> iso td's (if any) ->
* periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh
*/
td->backptr = &uhci->fl->frame[framenum];
td->link = uhci->fl->frame[framenum];
if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
- nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+ nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
nexttd->backptr = &td->link;
}
wmb();
spin_lock_irqsave(&framelist_lock, flags);
*(td->backptr) = td->link;
if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
- nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+ nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
nexttd->backptr = td->backptr;
}
spin_unlock_irqrestore(&framelist_lock, flags);
unsigned frn = inw(uhci->io_addr + USBFRNUM);
__u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES];
if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
- struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15);
+ struct uhci_td *tdl = (struct uhci_td *)uhci_ptr_to_virt(link);
for (;;) {
if (tdl == td) {
printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n");
}
if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH))
break;
- tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15);
+ tdl = (struct uhci_td *)uhci_ptr_to_virt(tdl->link);
}
- }
+ }
}
}
/* Remove it from the skeleton */
uhci_remove_qh(td->qh->skel, td->qh);
uhci_qh_free(td->qh);
+
do {
nextlink = curtd->link;
uhci_remove_td(curtd);
uhci_td_free(curtd);
+
if (nextlink & UHCI_PTR_TERM) /* Tail? */
break;
- curtd = bus_to_virt(nextlink & ~UHCI_PTR_BITS);
+ curtd = (struct uhci_td *)uhci_ptr_to_virt(nextlink);
if (!--maxcount) {
printk(KERN_ERR "runaway td's!?\n");
break;
}
/*
- * Request a interrupt handler..
+ * Request an interrupt handler..
*
* Returns 0 (success) or negative (failure).
* Also returns/sets a "handle pointer" that release_irq can use to stop this
td->bandwidth_alloc = bustime;
/* if period 0, set _REMOVE flag */
- if (period == 0) {
+ if (!period)
td->flags |= UHCI_TD_REMOVE;
- }
qh->skel = &dev->uhci->skelqh[__interval_to_skel(period)];
*
* This function can NOT be called from an interrupt.
*/
-int uhci_release_irq(struct usb_device *usb, void *handle)
+static int uhci_release_irq(struct usb_device *usb, void *handle)
{
struct uhci_td *td;
struct uhci_qh *qh;
if (!td)
return USB_ST_INTERNALERROR;
+ qh = td->qh;
+
/* Remove it from the internal irq_list */
uhci_remove_irq_list(td);
/* Remove the interrupt TD and QH */
uhci_remove_td(td);
- qh = td->qh;
uhci_remove_qh(qh->skel, qh);
if (td->completed != NULL)
*/
static int uhci_init_isoc (struct usb_device *usb_dev,
unsigned int pipe,
- int frame_count, /* bandwidth % = 100 * this / 1000 */
+ int frame_count, /* bandwidth % = 100 * this / 1024 */
void *context,
struct usb_isoc_desc **isocdesc)
{
}
} /* end START_RELATIVE */
else
- if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
+ if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame);
if (ix < START_FRAME_FUDGE || /* too small */
ix > CAN_SCHEDULE_FRAMES) { /* too large */
td->completed = isocdesc->callback_fn;
uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc); /* TBD: D.K. ??? */
}
+
return 0;
} /* end uhci_run_isoc */
}
for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) {
+ /* Deactivate and unlink */
uhci_remove_frame_list(uhci, td);
td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
} /* end for ix */
if (isocdesc->start_frame >= 0)
uhci_kill_isoc(isocdesc);
- /* Remove all td's from the IRQ list. */
- for(i = 0; i < isocdesc->frame_count; i++)
- uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i);
+ /* Remove all TD's from the IRQ list. */
+ for (i = 0; i < isocdesc->frame_count; i++)
+ uhci_remove_irq_list(((struct uhci_td *)isocdesc->td) + i);
/* Free the associate memory. */
if (isocdesc->td)
* there is no restriction on length of transfers
* anymore
*/
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout)
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd,
+ void *data, int len, int timeout)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
prevtd = td;
td = uhci_td_alloc(dev);
- if (!td)
- return -ENOMEM;
+ if (!td) {
+ uhci_td_free(prevtd);
+ return -ENOMEM;
+ }
prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
if (uhci_debug && ret) {
__u8 *p = (__u8 *)cmd;
+ printk("dev %d, pipe %X requested %ld bytes, got %ld, status=%d:\n",
+ usb_dev->devnum, pipe, bytesrequested, bytesread, ret);
printk(KERN_DEBUG "Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
}
+
return ret;
}
if (!td)
return -ENOMEM;
- prevtd = first; //This is fake, but at least it's not NULL
+ prevtd = first; // This is fake, but at least it's not NULL
while (len > 0) {
/* Build the TD for control status */
int pktsze = len;
usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
}
- td->link = 1; /* Terminate */
+ td->link = UHCI_PTR_TERM; /* Terminate */
td->status |= TD_CTRL_IOC;
/* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
} while (nr < maxchild);
}
-#if 0
static int fixup_isoc_desc (struct uhci_td *td)
{
struct usb_isoc_desc *isocdesc = td->dev_id;
if ((frm->frame_status = uhci_map_status (uhci_status_bits (prtd->status),
uhci_packetout (prtd->info))))
isocdesc->error_count++;
-
+
prtd++;
frm++;
if (++fx >= isocdesc->frame_count) { /* wrap fx, prtd, and frm */
return 0;
}
-#endif /* 0 */
+int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval)
+{
+ struct usb_isoc_desc *isocdesc = td->dev_id;
+ int ret;
+
+ /*
+ * Fixup the isocdesc for the driver: total_completed_frames,
+ * error_count, total_length, frames array.
+ *
+ * ret = callback_fn (int error_count, void *buffer,
+ * int len, void *isocdesc);
+ */
+
+ fixup_isoc_desc (td);
+
+ ret = td->completed (isocdesc->error_count, bus_to_virt (td->buffer),
+ isocdesc->total_length, isocdesc);
+
+ /*
+ * Isoc. handling of return value from td->completed (callback function)
+ */
+
+ switch (ret) {
+ case CB_CONTINUE: /* similar to the REMOVE condition below */
+ /* TBD */
+ uhci_td_free (td);
+ break;
+
+ case CB_REUSE: /* similar to the re-add condition below,
+ * but Not ACTIVE */
+ /* TBD */
+ /* usb_dev = td->dev->usb; */
+
+ list_add(&td->irq_list, &uhci->interrupt_list);
+
+ td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK |
+ TD_CTRL_LS | TD_CTRL_IOS | TD_CTRL_IOC)) |
+ TD_CTRL_IOC;
+
+ /* The HC removes it, so re-add it */
+ /* Insert into a QH? */
+ uhci_insert_td_in_qh(td->qh, td);
+ break;
+
+ case CB_RESTART: /* similar to re-add, but mark ACTIVE */
+ /* TBD */
+ /* usb_dev = td->dev->usb; */
+
+ list_add(&td->irq_list, &uhci->interrupt_list);
+
+ td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK |
+ TD_CTRL_LS | TD_CTRL_IOS | TD_CTRL_IOC)) |
+ TD_CTRL_ACTIVE | TD_CTRL_IOC;
+
+ /* The HC removes it, so re-add it */
+ uhci_insert_td_in_qh(td->qh, td);
+ break;
+
+ case CB_ABORT: /* kill/abort */
+ /* TBD */
+ uhci_kill_isoc (isocdesc);
+ break;
+ } /* end isoc. TD switch */
+
+ return 0;
+}
+
+int uhci_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval)
+{
+ if (td->completed(status, bus_to_virt(td->buffer), rval, td->dev_id)) {
+ struct usb_device *usb_dev = td->dev->usb;
+
+ list_add(&td->irq_list, &uhci->interrupt_list);
+
+ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
+ td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */
+ td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info),
+ uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */
+ td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+ /* The HC only removes it when it completed */
+ /* successfully, so force remove and re-add it. */
+ uhci_remove_td(td);
+ uhci_insert_td_in_qh(td->qh, td);
+ } else if (td->flags & UHCI_TD_REMOVE) {
+ struct usb_device *usb_dev = td->dev->usb;
+
+ /* marked for removal */
+ td->flags &= ~UHCI_TD_REMOVE;
+ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), uhci_packetout(td->info));
+ uhci_remove_qh(td->qh->skel, td->qh);
+ uhci_qh_free(td->qh);
+ if (td->pipetype == PIPE_INTERRUPT)
+ usb_release_bandwidth(usb_dev, td->bandwidth_alloc);
+ uhci_td_free(td);
+ }
+
+ return 0;
+}
+
static void uhci_interrupt_notify(struct uhci *uhci)
{
struct list_head *tmp, *head = &uhci->interrupt_list;
list_del(&td->irq_list);
INIT_LIST_HEAD(&td->irq_list);
- if (td->completed(status, bus_to_virt(td->buffer), rval,
- td->dev_id)) {
- struct usb_device *usb_dev = td->dev->usb;
-
- list_add(&td->irq_list, &uhci->interrupt_list);
-
- usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
- td->info &= ~(1 << 19); /* clear data toggle */
- td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info),
- uhci_packetout(td->info)) << 19; /* toggle between data0 and data1 */
- td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
- /* The HC only removes it when it completed */
- /* successfully, so force remove and re-add it */
- uhci_remove_td(td);
- uhci_insert_td_in_qh(td->qh, td);
- } else if (td->flags & UHCI_TD_REMOVE) {
- struct usb_device *usb_dev = td->dev->usb;
-
- /* marked for removal */
- td->flags &= ~UHCI_TD_REMOVE;
- usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), uhci_packetout(td->info));
- uhci_remove_qh(td->qh->skel, td->qh);
- uhci_qh_free(td->qh);
- uhci_td_free(td);
- if (td->pipetype == PIPE_INTERRUPT)
- usb_release_bandwidth(usb_dev, td->bandwidth_alloc);
+ if (td->pipetype == PIPE_ISOCHRONOUS) {
+ uhci_isoc_callback(uhci, td, status, rval);
+ }
+ else {
+ uhci_callback(uhci, td, status, rval);
}
/* If completed does not wants to reactivate, then */
td->link = uhci->fl->frame[0];
td->backptr = &uhci->fl->frame[0];
td->status = TD_CTRL_IOC;
- td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; /* (ignored) input packet, 16 bytes, device 127 */
+ td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN;
+ /* (ignored) input packet, 16 bytes, device 127 */
td->buffer = 0;
td->qh = NULL;
td->pipetype = -1;
#define TD_TOKEN_TOGGLE 19
#define uhci_maxlen(token) ((token) >> 21)
+#define uhci_expected_length(info) ((info >> 21) + 1) /* 1-based */
#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1)
#define uhci_endpoint(token) (((token) >> 15) & 0xf)
#define uhci_devaddr(token) (((token) >> 8) & 0x7f)
*/
struct uhci;
-#if 0
-#define UHCI_MAXTD 64
-
-#define UHCI_MAXQH 16
-#endif
-
/* The usb device part must be first! Not anymore -jerdfelt */
struct uhci_device {
struct usb_device *usb;
atomic_t refcnt;
struct uhci *uhci;
-#if 0
- struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */
- struct uhci_td td[UHCI_MAXTD];
-#endif
unsigned long data[16];
};
* and we should meet that frequency when requested to do so.
* This will require some change(s) to the UHCI skeleton.
*/
-static inline int __interval_to_skel(interval)
+static inline int __interval_to_skel(int interval)
{
if (interval < 16) {
if (interval < 4) {
dr.index = 1;
dr.length = 0;
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
- return -1;
-
- return 0;
+ return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ);
}
/* keyboards want a nonzero duration according to HID spec, but
dr.index = 1;
dr.length = 0;
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
- return -1;
-
- return 0;
+ return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ);
}
static void usb_set_maxpacket(struct usb_device *dev)
if (result)
return result;
- if (status & 1)
- return 1; /* still halted */
+ if (status & 1) /* endpoint status is Halted */
+ return USB_ST_STALL; /* still halted */
#endif
usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp));
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
devrequest dr;
+ int err;
dr.requesttype = 1;
dr.request = USB_REQ_SET_INTERFACE;
dr.index = interface;
dr.length = 0;
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
- return -1;
+ err = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ);
+ if (err)
+ return err;
dev->ifnum = interface;
dev->actconfig->interface[interface].act_altsetting = alternate;
dr.index = index;
dr.length = size;
- if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ))
- return -1;
-
- return 0;
+ return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ);
}
int usb_get_configuration(struct usb_device *dev)
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
* get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
*/
int usb_new_device(struct usb_device *dev)
{
int addr;
+ int err;
printk(KERN_INFO "USB new device connect, assigned device number %d\n",
dev->devnum);
dev->devnum = 0;
/* Slow devices */
- if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) {
- printk(KERN_ERR "usbcore: USB device not responding, giving up\n");
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+ if (err) {
+ printk(KERN_ERR "usbcore: USB device not responding, giving up (error=%d)\n",
+ err);
dev->devnum = -1;
return 1;
}
dev->devnum = addr;
- if (usb_set_address(dev)) {
- printk(KERN_ERR "usbcore: USB device not accepting new address\n");
+ err = usb_set_address(dev);
+ if (err) {
+ printk(KERN_ERR "usbcore: USB device not accepting new address (error=%d)\n",
+ err);
dev->devnum = -1;
return 1;
}
wait_ms(10); /* Let the SET_ADDRESS settle */
- if (usb_get_device_descriptor(dev)) {
- printk(KERN_ERR "usbcore: unable to get device descriptor\n");
+ err = usb_get_device_descriptor(dev);
+ if (err) {
+ printk(KERN_ERR "usbcore: unable to get device descriptor (error=%d)\n",
+ err);
dev->devnum = -1;
return 1;
}
if (register_chrdev(180,"usb",&usb_fops)) {
printk("unable to get major %d for usb devices\n",
MISC_MAJOR);
- return -EIO;
}
}
} devrequest __attribute__ ((packed));
/*
- * Status codes (these follow OHCI controllers condition codes)
+ * Status codes (these [used to] follow OHCI controllers condition codes)
*/
-#define USB_ST_NOERROR 0x0
-#define USB_ST_CRC 0x1
-#define USB_ST_BITSTUFF 0x2
-#define USB_ST_DTMISMATCH 0x3 /* data toggle mismatch */
-#define USB_ST_STALL 0x4
-#define USB_ST_NORESPONSE 0x5 /* device not responding/handshaking */
-#define USB_ST_PIDCHECK 0x6 /* Check bits on PID failed */
-#define USB_ST_PIDUNDEF 0x7 /* PID unexpected/undefined */
-#define USB_ST_DATAOVERRUN 0x8
-#define USB_ST_DATAUNDERRUN 0x9
-#define USB_ST_RESERVED1 0xA
-#define USB_ST_RESERVED2 0xB
-#define USB_ST_BUFFEROVERRUN 0xC
-#define USB_ST_BUFFERUNDERRUN 0xD
-#define USB_ST_RESERVED3 0xE
-#define USB_ST_RESERVED4 0xF
+#define USB_ST_NOERROR 0
+#define USB_ST_CRC -1
+#define USB_ST_BITSTUFF -2
+#define USB_ST_DTMISMATCH -3 /* data toggle mismatch */
+#define USB_ST_STALL -4
+#define USB_ST_NORESPONSE -5 /* device not responding/handshaking */
+#define USB_ST_PIDCHECK -6 /* Check bits on PID failed */
+#define USB_ST_PIDUNDEF -7 /* PID unexpected/undefined */
+#define USB_ST_DATAOVERRUN -8
+#define USB_ST_DATAUNDERRUN -9
+#define USB_ST_RESERVED1 -10
+#define USB_ST_RESERVED2 -11
+#define USB_ST_BUFFEROVERRUN -12
+#define USB_ST_BUFFERUNDERRUN -13
+#define USB_ST_RESERVED3 -14
+#define USB_ST_RESERVED4 -15
/* internal errors */
-#define USB_ST_REMOVED 0x100
-#define USB_ST_TIMEOUT 0x110
-#define USB_ST_INTERNALERROR -1
-#define USB_ST_NOTSUPPORTED -2
-#define USB_ST_BANDWIDTH_ERROR -3
+#define USB_ST_REMOVED -100
+#define USB_ST_TIMEOUT -101
+#define USB_ST_INTERNALERROR -200
+#define USB_ST_NOTSUPPORTED -201
+#define USB_ST_BANDWIDTH_ERROR -202
+#define USB_ST_NOCHANGE -203
/*
int usb_set_protocol(struct usb_device *dev, int protocol);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
int usb_set_idle(struct usb_device *dev, int duration, int report_id);
-int usb_set_interface(struct usb_device *dev, int interface, int alternate);
int usb_set_configuration(struct usb_device *dev, int configuration);
int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size);
char *usb_string(struct usb_device *dev, int index);
bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
fi
tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
+ bool ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
fi
fi
endif
endif
+ifeq ($(CONFIG_FB_ATY128),y)
+L_OBJS += aty128fb.o
+endif
+
ifeq ($(CONFIG_FB_IGA),y)
L_OBJS += igafb.o
endif
--- /dev/null
+/* $Id: aty128.h,v 1.1 1999/10/12 11:00:40 geert Exp $
+ * linux/drivers/video/aty128.h
+ * Register definitions for ATI Rage128 boards
+ *
+ * Anthony Tong <atong@uiuc.edu>, 1999
+ */
+
+#ifndef REG_RAGE128_H
+#define REG_RAGE128_H
+
+#define MM_INDEX 0x0000
+#define MM_DATA 0x0004
+#define CLOCK_CNTL_INDEX 0x0008
+#define CLOCK_CNTL_DATA 0x000c
+#define BIOS_0_SCRATCH 0x0010
+#define BIOS_1_SCRATCH 0x0014
+#define BIOS_2_SCRATCH 0x0018
+#define BIOS_3_SCRATCH 0x001c
+#define BUS_CNTL 0x0030
+#define BUS_CNTL1 0x0034
+#define MEM_VGA_WP_SEL 0x0038
+#define MEM_VGA_RP_SEL 0x003c
+#define GEN_INT_CNTL 0x0040
+#define GEN_INT_STATUS 0x0044
+#define CRTC_GEN_CNTL 0x0050
+#define CRTC_EXT_CNTL 0x0054
+#define DAC_CNTL 0x0058
+#define CRTC_STATUS 0x005c
+#define GPIO_MONID 0x0068
+#define I2C_CNTL_1 0x0094
+#define PALETTE_INDEX 0x00b0
+#define PALETTE_DATA 0x00b4
+#define CONFIG_CNTL 0x00e0
+#define CONFIG_XSTRAP 0x00e4
+#define CONFIG_BONDS 0x00e8
+#define GEN_RESET_CNTL 0x00f0
+#define GEN_STATUS 0x00f4
+#define CONFIG_MEMSIZE 0x00f8
+#define CONFIG_APER_0_BASE 0x0100
+#define CONFIG_APER_1_BASE 0x0104
+#define CONFIG_APER_SIZE 0x0108
+#define CONFIG_REG_1_BASE 0x010c
+#define CONFIG_REG_APER_SIZE 0x0110
+#define CONFIG_MEMSIZE_EMBEDDED 0x0114
+#define TEST_DEBUG_CNTL 0x0120
+#define TEST_DEBUG_MUX 0x0124
+#define HW_DEBUG 0x0128
+#define TEST_DEBUG_OUT 0x012c
+#define HOST_PATH_CNTL 0x0130
+#define SW_SEMAPHORE 0x013c
+#define MEM_CNTL 0x0140
+#define EXT_MEM_CNTL 0x0144
+#define MEM_ADDR_CONFIG 0x0148
+#define MEM_INTF_CNTL 0x014c
+#define MEM_STR_CNTL 0x0150
+#define MEM_INIT_LAT_TIMER 0x0154
+#define MEM_SDRAM_MODE_REG 0x0158
+#define AGP_BASE 0x0170
+#define AGP_CNTL 0x0174
+#define AGP_APER_OFFSET 0x0178
+#define PCI_GART_PAGE 0x017c
+#define PC_NGUI_MODE 0x0180
+#define PC_NGUI_CTLSTAT 0x0184
+#define VIDEOMUX_CNTL 0x0190
+#define MPP_TB_CONFIG 0x01C0
+#define MPP_GP_CONFIG 0x01C8
+#define VIPH_CONTROL 0x01D0
+#define CRTC_H_TOTAL_DISP 0x0200
+#define CRTC_H_SYNC_STRT_WID 0x0204
+#define CRTC_V_TOTAL_DISP 0x0208
+#define CRTC_V_SYNC_STRT_WID 0x020c
+#define CRTC_VLINE_CRNT_VLINE 0x0210
+#define CRTC_CRNT_FRAME 0x0214
+#define CRTC_GUI_TRIG_VLINE 0x0218
+#define CRTC_DEBUG 0x021c
+#define CRTC_OFFSET 0x0224
+#define CRTC_OFFSET_CNTL 0x0228
+#define CRTC_PITCH 0x022c
+#define OVR_CLR 0x0230
+#define OVR_WID_LEFT_RIGHT 0x0234
+#define OVR_WID_TOP_BOTTOM 0x0238
+#define SNAPSHOT_VH_COUNTS 0x0240
+#define SNAPSHOT_F_COUNT 0x0244
+#define N_VIF_COUNT 0x0248
+#define SNAPSHOT_VIF_COUNT 0x024c
+#define CUR_OFFSET 0x0260
+#define CUR_HORZ_VERT_POSN 0x0264
+#define CUR_HORZ_VERT_OFF 0x0268
+#define CUR_CLR0 0x026c
+#define CUR_CLR1 0x0270
+#define DAC_CRC_SIG 0x02cc
+#define DDA_CONFIG 0x02e0
+#define DDA_ON_OFF 0x02e4
+#define VGA_DDA_CONFIG 0x02e8
+#define VGA_DDA_ON_OFF 0x02ec
+#define OV0_Y_X_START 0x0400
+#define OV0_Y_X_END 0x0404
+#define OV0_EXCLUSIVE_HORZ 0x0408
+#define OV0_EXCLUSIVE_VERT 0x040c
+#define OV0_REG_LOAD_CNTL 0x0410
+#define OV0_SCALE_CNTL 0x0420
+#define OV0_V_INC 0x0424
+#define OV0_P1_V_ACCUM_INIT 0x0428
+#define OV0_P23_V_ACCUM_INIT 0x042c
+#define OV0_P1_BLANK_LINES_AT_TOP 0x0430
+#define OV0_P23_BLANK_LINES_AT_TOP 0x0434
+#define OV0_VID_BUF0_BASE_ADRS 0x0440
+#define OV0_VID_BUF1_BASE_ADRS 0x0444
+#define OV0_VID_BUF2_BASE_ADRS 0x0448
+#define OV0_VID_BUF3_BASE_ADRS 0x044c
+#define OV0_VID_BUF4_BASE_ADRS 0x0450
+#define OV0_VID_BUF5_BASE_ADRS 0x0454
+#define OV0_VID_BUF_PITCH0_VALUE 0x0460
+#define OV0_VID_BUF_PITCH1_VALUE 0x0464
+#define OV0_OCTWORDS_PER_LINE_M1 0x046c
+#define OV0_AUTO_FLIP_CNTRL 0x0470
+#define OV0_DEINTERLACE_PATTERN 0x0474
+#define OV0_H_INC 0x0480
+#define OV0_STEP_BY 0x0484
+#define OV0_P1_H_ACCUM_INIT 0x0488
+#define OV0_P23_H_ACCUM_INIT 0x048c
+#define OV0_P1_X_START_END 0x0494
+#define OV0_P2_X_START_END 0x0498
+#define OV0_P3_X_START_END 0x049c
+#define OV0_FILTER_CNTL 0x04a0
+#define OV0_FOUR_TAP_COEF_0 0x04b0
+#define OV0_FOUR_TAP_COEF_1 0x04b4
+#define OV0_FOUR_TAP_COEF_2 0x04b8
+#define OV0_FOUR_TAP_COEF_3 0x04bc
+#define OV0_FOUR_TAP_COEF_4 0x04c0
+#define OV0_COLOR_CNTL 0x04e0
+#define OV0_VIDEO_KEY_CLR 0x04e4
+#define OV0_VIDEO_KEY_MASK 0x04e8
+#define OV0_GRAPHICS_KEY_CLR 0x04ec
+#define OV0_GRAPHICS_KEY_MASK 0x04f0
+#define OV0_KEY_CNTL 0x04f4
+#define OV0_TEST 0x04f8
+#define SUBPIC_CNTL 0x0540
+#define PM4_BUFFER_OFFSET 0x0700
+#define PM4_BUFFER_CNTL 0x0704
+#define PM4_BUFFER_WM_CNTL 0x0708
+#define PM4_BUFFER_DL_RPTR_ADDR 0x070c
+#define PM4_BUFFER_DL_RPTR 0x0710
+#define PM4_BUFFER_DL_WPTR 0x0714
+#define PM4_VC_FPU_SETUP 0x071c
+#define PM4_FPU_CNTL 0x0720
+#define PM4_VC_FORMAT 0x0724
+#define PM4_VC_CNTL 0x0728
+#define PM4_VC_I01 0x072c
+#define PM4_VC_VLOFF 0x0730
+#define PM4_VC_VLSIZE 0x0734
+#define PM4_IW_INDOFF 0x0738
+#define PM4_IW_INDSIZE 0x073c
+#define PM4_FPU_FPX0 0x0740
+#define CRC_CMDFIFO_ADDR 0x0740
+#define PM4_FPU_FPY0 0x0744
+#define CRC_CMDFIFO_DOUT 0x0744
+#define PM4_FPU_FPX1 0x0748
+#define PM4_FPU_FPY1 0x074c
+#define PM4_FPU_FPX2 0x0750
+#define PM4_FPU_FPY2 0x0754
+#define PM4_FPU_FPY3 0x0758
+#define PM4_FPU_FPY4 0x075c
+#define PM4_FPU_FPY5 0x0760
+#define PM4_FPU_FPY6 0x0764
+#define PM4_FPU_FPR 0x0768
+#define PM4_FPU_FPG 0x076c
+#define PM4_FPU_FPB 0x0770
+#define PM4_FPU_FPA 0x0774
+#define PM4_FPU_INTXY0 0x0780
+#define PM4_FPU_INTXY1 0x0784
+#define PM4_FPU_INTXY2 0x0788
+#define PM4_FPU_INTARGB 0x078c
+#define PM4_FPU_FPTWICEAREA 0x0790
+#define PM4_FPU_DMAJOR01 0x0794
+#define PM4_FPU_DMAJOR12 0x0798
+#define PM4_FPU_DMAJOR02 0x079c
+#define PM4_FPU_STAT 0x07a0
+#define PM4_STAT 0x07b8
+#define PM4_TEST_CNTL 0x07d0
+#define PM4_MICROCODE_ADDR 0x07d4
+#define PM4_MICROCODE_RADDR 0x07d8
+#define PM4_MICROCODE_DATAH 0x07dc
+#define PM4_MICROCODE_DATAL 0x07e0
+#define PM4_CMDFIFO_ADDR 0x07e4
+#define PM4_CMDFIFO_DATAH 0x07e8
+#define PM4_CMDFIFO_DATAL 0x07ec
+#define PM4_BUFFER_ADDR 0x07f0
+#define PM4_BUFFER_DATAH 0x07f4
+#define PM4_BUFFER_DATAL 0x07f8
+#define PM4_MICRO_CNTL 0x07fc
+#define VID_BUFFER_CONTROL 0x0900
+#define CAP_INT_CNTL 0x0908
+#define CAP_INT_STATUS 0x090c
+#define CAP0_BUF0_OFFSET 0x0920
+#define CAP0_BUF1_OFFSET 0x0924
+#define CAP0_BUF0_EVEN_OFFSET 0x0928
+#define CAP0_BUF1_EVEN_OFFSET 0x092c
+#define CAP0_BUF_PITCH 0x0930
+#define CAP0_V_WINDOW 0x0934
+#define CAP0_H_WINDOW 0x0938
+#define CAP0_VBI_ODD_OFFSET 0x093c
+#define CAP0_VBI_EVEN_OFFSET 0x0940
+#define CAP0_VBI_V_WINDOW 0x0944
+#define CAP0_VBI_H_WINDOW 0x0948
+#define CAP0_PORT_MODE_CNTL 0x094c
+#define CAP0_TRIG_CNTL 0x0950
+#define CAP0_DEBUG 0x0954
+#define CAP0_CONFIG 0x0958
+#define CAP0_ANC_ODD_OFFSET 0x095c
+#define CAP0_ANC_EVEN_OFFSET 0x0960
+#define CAP0_ANC_H_WINDOW 0x0964
+#define CAP0_VIDEO_SYNC_TEST 0x0968
+#define CAP0_ONESHOT_BUF_OFFSET 0x096c
+#define CAP0_BUF_STATUS 0x0970
+#define CAP0_DWNSC_XRATIO 0x0978
+#define CAP0_XSHARPNESS 0x097c
+#define CAP1_BUF0_OFFSET 0x0990
+#define CAP1_BUF1_OFFSET 0x0994
+#define CAP1_BUF0_EVEN_OFFSET 0x0998
+#define CAP1_BUF1_EVEN_OFFSET 0x099c
+#define CAP1_BUF_PITCH 0x09a0
+#define CAP1_V_WINDOW 0x09a4
+#define CAP1_H_WINDOW 0x09a8
+#define CAP1_VBI_ODD_OFFSET 0x09ac
+#define CAP1_VBI_EVEN_OFFSET 0x09b0
+#define CAP1_VBI_V_WINDOW 0x09b4
+#define CAP1_VBI_H_WINDOW 0x09b8
+#define CAP1_PORT_MODE_CNTL 0x09bc
+#define CAP1_TRIG_CNTL 0x09c0
+#define CAP1_DEBUG 0x09c4
+#define CAP1_CONFIG 0x09c8
+#define CAP1_ANC_ODD_OFFSET 0x09cc
+#define CAP1_ANC_EVEN_OFFSET 0x09d0
+#define CAP1_ANC_H_WINDOW 0x09d4
+#define CAP1_VIDEO_SYNC_TEST 0x09d8
+#define CAP1_ONESHOT_BUF_OFFSET 0x09dc
+#define CAP1_BUF_STATUS 0x09e0
+#define CAP1_DWNSC_XRATIO 0x09e8
+#define CAP1_XSHARPNESS 0x09ec
+#define BM_FRAME_BUF_OFFSET 0x0a00
+#define BM_SYSTEM_MEM_ADDR 0x0a04
+#define BM_COMMAND 0x0a08
+#define BM_STATUS 0x0a0c
+#define BM_QUEUE_STATUS 0x0a10
+#define BM_QUEUE_FREE_STATUS 0x0A14
+#define BM_CHUNK_0_VAL 0x0a18
+#define BM_CHUNK_1_VAL 0x0a1C
+#define BM_VIP0_BUF 0x0A20
+#define BM_VIP0_ACTIVE 0x0A24
+#define BM_VIP1_BUF 0x0A30
+#define BM_VIP1_ACTIVE 0x0A34
+#define BM_VIP2_BUF 0x0A40
+#define BM_VIP2_ACTIVE 0x0A44
+#define BM_VIP3_BUF 0x0A50
+#define BM_VIP3_ACTIVE 0x0A54
+#define BM_VIDCAP_BUF0 0x0a60
+#define BM_VIDCAP_BUF1 0x0a64
+#define BM_VIDCAP_BUF2 0x0a68
+#define BM_VIDCAP_ACTIVE 0x0a6c
+#define BM_GUI 0x0a80
+#define SURFACE_DELAY 0x0b00
+
+/******************************************************************************
+ * GUI Block Memory Mapped Registers *
+ * These registers are FIFOed. *
+ *****************************************************************************/
+#define PM4_FIFO_DATA_EVEN 0x1000
+#define PM4_FIFO_DATA_ODD 0x1004
+
+#define DST_OFFSET 0x1404
+#define DST_PITCH 0x1408
+#define DST_WIDTH 0x140c
+#define DST_HEIGHT 0x1410
+#define SRC_X 0x1414
+#define SRC_Y 0x1418
+#define DST_X 0x141c
+#define DST_Y 0x1420
+#define SRC_PITCH_OFFSET 0x1428
+#define DST_PITCH_OFFSET 0x142c
+#define SRC_Y_X 0x1434
+#define DST_Y_X 0x1438
+#define DST_HEIGHT_WIDTH 0x143c
+#define DP_GUI_MASTER_CNTL 0x146c
+#define BRUSH_SCALE 0x1470
+#define BRUSH_Y_X 0x1474
+#define DP_BRUSH_BKGD_CLR 0x1478
+#define DP_BRUSH_FRGD_CLR 0x147c
+#define BRUSH_DATA0 0x1480
+#define BRUSH_DATA1 0x1484
+#define BRUSH_DATA2 0x1488
+#define BRUSH_DATA3 0x148c
+#define BRUSH_DATA4 0x1490
+#define BRUSH_DATA5 0x1494
+#define BRUSH_DATA6 0x1498
+#define BRUSH_DATA7 0x149c
+#define BRUSH_DATA8 0x14a0
+#define BRUSH_DATA9 0x14a4
+#define BRUSH_DATA10 0x14a8
+#define BRUSH_DATA11 0x14ac
+#define BRUSH_DATA12 0x14b0
+#define BRUSH_DATA13 0x14b4
+#define BRUSH_DATA14 0x14b8
+#define BRUSH_DATA15 0x14bc
+#define BRUSH_DATA16 0x14c0
+#define BRUSH_DATA17 0x14c4
+#define BRUSH_DATA18 0x14c8
+#define BRUSH_DATA19 0x14cc
+#define BRUSH_DATA20 0x14d0
+#define BRUSH_DATA21 0x14d4
+#define BRUSH_DATA22 0x14d8
+#define BRUSH_DATA23 0x14dc
+#define BRUSH_DATA24 0x14e0
+#define BRUSH_DATA25 0x14e4
+#define BRUSH_DATA26 0x14e8
+#define BRUSH_DATA27 0x14ec
+#define BRUSH_DATA28 0x14f0
+#define BRUSH_DATA29 0x14f4
+#define BRUSH_DATA30 0x14f8
+#define BRUSH_DATA31 0x14fc
+#define BRUSH_DATA32 0x1500
+#define BRUSH_DATA33 0x1504
+#define BRUSH_DATA34 0x1508
+#define BRUSH_DATA35 0x150c
+#define BRUSH_DATA36 0x1510
+#define BRUSH_DATA37 0x1514
+#define BRUSH_DATA38 0x1518
+#define BRUSH_DATA39 0x151c
+#define BRUSH_DATA40 0x1520
+#define BRUSH_DATA41 0x1524
+#define BRUSH_DATA42 0x1528
+#define BRUSH_DATA43 0x152c
+#define BRUSH_DATA44 0x1530
+#define BRUSH_DATA45 0x1534
+#define BRUSH_DATA46 0x1538
+#define BRUSH_DATA47 0x153c
+#define BRUSH_DATA48 0x1540
+#define BRUSH_DATA49 0x1544
+#define BRUSH_DATA50 0x1548
+#define BRUSH_DATA51 0x154c
+#define BRUSH_DATA52 0x1550
+#define BRUSH_DATA53 0x1554
+#define BRUSH_DATA54 0x1558
+#define BRUSH_DATA55 0x155c
+#define BRUSH_DATA56 0x1560
+#define BRUSH_DATA57 0x1564
+#define BRUSH_DATA58 0x1568
+#define BRUSH_DATA59 0x156c
+#define BRUSH_DATA60 0x1570
+#define BRUSH_DATA61 0x1574
+#define BRUSH_DATA62 0x1578
+#define BRUSH_DATA63 0x157c
+#define DST_WIDTH_X 0x1588
+#define DST_HEIGHT_WIDTH_8 0x158c
+#define SRC_X_Y 0x1590
+#define DST_X_Y 0x1594
+#define DST_WIDTH_HEIGHT 0x1598
+#define DST_WIDTH_X_INCY 0x159c
+#define DST_HEIGHT_Y 0x15a0
+#define DST_X_SUB 0x15a4
+#define DST_Y_SUB 0x15a8
+#define SRC_OFFSET 0x15ac
+#define SRC_PITCH 0x15b0
+#define DST_HEIGHT_WIDTH_BW 0x15b4
+#define CLR_CMP_CNTL 0x15c0
+#define CLR_CMP_CLR_SRC 0x15c4
+#define CLR_CMP_CLR_DST 0x15c8
+#define CLR_CMP_MASK 0x15cc
+#define DP_SRC_FRGD_CLR 0x15d8
+#define DP_SRC_BKGD_CLR 0x15dc
+#define GUI_SCRATCH_REG0 0x15e0
+#define GUI_SCRATCH_REG1 0x15e4
+#define GUI_SCRATCH_REG2 0x15e8
+#define GUI_SCRATCH_REG3 0x15ec
+#define GUI_SCRATCH_REG4 0x15f0
+#define GUI_SCRATCH_REG5 0x15f4
+#define LEAD_BRES_ERR 0x1600
+#define LEAD_BRES_INC 0x1604
+#define LEAD_BRES_DEC 0x1608
+#define TRAIL_BRES_ERR 0x160c
+#define TRAIL_BRES_INC 0x1610
+#define TRAIL_BRES_DEC 0x1614
+#define TRAIL_X 0x1618
+#define LEAD_BRES_LNTH 0x161c
+#define TRAIL_X_SUB 0x1620
+#define LEAD_BRES_LNTH_SUB 0x1624
+#define DST_BRES_ERR 0x1628
+#define DST_BRES_INC 0x162c
+#define DST_BRES_DEC 0x1630
+#define DST_BRES_LNTH 0x1634
+#define DST_BRES_LNTH_SUB 0x1638
+#define SC_LEFT 0x1640
+#define SC_RIGHT 0x1644
+#define SC_TOP 0x1648
+#define SC_BOTTOM 0x164c
+#define SRC_SC_RIGHT 0x1654
+#define SRC_SC_BOTTOM 0x165c
+#define AUX_SC_CNTL 0x1660
+#define AUX1_SC_LEFT 0x1664
+#define AUX1_SC_RIGHT 0x1668
+#define AUX1_SC_TOP 0x166c
+#define AUX1_SC_BOTTOM 0x1670
+#define AUX2_SC_LEFT 0x1674
+#define AUX2_SC_RIGHT 0x1678
+#define AUX2_SC_TOP 0x167c
+#define AUX2_SC_BOTTOM 0x1680
+#define AUX3_SC_LEFT 0x1684
+#define AUX3_SC_RIGHT 0x1688
+#define AUX3_SC_TOP 0x168c
+#define AUX3_SC_BOTTOM 0x1690
+#define GUI_DEBUG0 0x16a0
+#define GUI_DEBUG1 0x16a4
+#define GUI_TIMEOUT 0x16b0
+#define GUI_TIMEOUT0 0x16b4
+#define GUI_TIMEOUT1 0x16b8
+#define GUI_PROBE 0x16bc
+#define DP_CNTL 0x16c0
+#define DP_DATATYPE 0x16c4
+#define DP_MIX 0x16c8
+#define DP_WRITE_MASK 0x16cc
+#define DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0
+#define DEFAULT_OFFSET 0x16e0
+#define DEFAULT_PITCH 0x16e4
+#define DEFAULT_SC_BOTTOM_RIGHT 0x16e8
+#define SC_TOP_LEFT 0x16ec
+#define SC_BOTTOM_RIGHT 0x16f0
+#define SRC_SC_BOTTOM_RIGHT 0x16f4
+#define WAIT_UNTIL 0x1720
+#define CACHE_CNTL 0x1724
+#define GUI_STAT 0x1740
+#define PC_GUI_MODE 0x1744
+#define PC_GUI_CTLSTAT 0x1748
+#define PC_DEBUG_MODE 0x1760
+#define BRES_DST_ERR_DEC 0x1780
+#define TRAIL_BRES_T12_ERR_DEC 0x1784
+#define TRAIL_BRES_T12_INC 0x1788
+#define DP_T12_CNTL 0x178c
+#define DST_BRES_T1_LNTH 0x1790
+#define DST_BRES_T2_LNTH 0x1794
+#define HOST_DATA0 0x17c0
+#define HOST_DATA1 0x17c4
+#define HOST_DATA2 0x17c8
+#define HOST_DATA3 0x17cc
+#define HOST_DATA4 0x17d0
+#define HOST_DATA5 0x17d4
+#define HOST_DATA6 0x17d8
+#define HOST_DATA7 0x17dc
+#define HOST_DATA_LAST 0x17e0
+#define SECONDARY_SCALE_PITCH 0x1980
+#define SECONDARY_SCALE_X_INC 0x1984
+#define SECONDARY_SCALE_Y_INC 0x1988
+#define SECONDARY_SCALE_HACC 0x198c
+#define SECONDARY_SCALE_VACC 0x1990
+#define SCALE_SRC_HEIGHT_WIDTH 0x1994
+#define SCALE_OFFSET_0 0x1998
+#define SCALE_PITCH 0x199c
+#define SCALE_X_INC 0x19a0
+#define SCALE_Y_INC 0x19a4
+#define SCALE_HACC 0x19a8
+#define SCALE_VACC 0x19ac
+#define SCALE_DST_X_Y 0x19b0
+#define SCALE_DST_HEIGHT_WIDTH 0x19b4
+#define SCALE_3D_CNTL 0x1a00
+#define SCALE_3D_DATATYPE 0x1a20
+#define SETUP_CNTL 0x1bc4
+#define SOLID_COLOR 0x1bc8
+#define WINDOW_XY_OFFSET 0x1bcc
+#define DRAW_LINE_POINT 0x1bd0
+#define SETUP_CNTL_PM4 0x1bd4
+#define DST_PITCH_OFFSET_C 0x1c80
+#define DP_GUI_MASTER_CNTL_C 0x1c84
+#define SC_TOP_LEFT_C 0x1c88
+#define SC_BOTTOM_RIGHT_C 0x1c8c
+
+#define CLR_CMP_MASK_3D 0x1A28
+#define MISC_3D_STATE_CNTL_REG 0x1CA0
+#define MC_SRC1_CNTL 0x19D8
+#define TEX_CNTL 0x1800
+
+/* CONSTANTS */
+#define GUI_ACTIVE 0x80000000
+#define ENGINE_IDLE 0x0
+
+#define PLL_WR_EN 0x00000080
+
+#define CLK_PIN_CNTL 0x0001
+#define PPLL_CNTL 0x0002
+#define PPLL_REF_DIV 0x0003
+#define PPLL_DIV_0 0x0004
+#define PPLL_DIV_1 0x0005
+#define PPLL_DIV_2 0x0006
+#define PPLL_DIV_3 0x0007
+#define VCLK_ECP_CNTL 0x0008
+#define HTOTAL_CNTL 0x0009
+#define X_MPLL_REF_FB_DIV 0x000a
+#define XPLL_CNTL 0x000b
+#define XDLL_CNTL 0x000c
+#define XCLK_CNTL 0x000d
+#define MPLL_CNTL 0x000e
+#define MCLK_CNTL 0x000f
+#define AGP_PLL_CNTL 0x0010
+#define FCP_CNTL 0x0012
+#define PLL_TEST_CNTL 0x0013
+
+#define PPLL_RESET 0x01
+#define PPLL_ATOMIC_UPDATE_EN 0x10000
+#define PPLL_VGA_ATOMIC_UPDATE_EN 0x20000
+#define PPLL_REF_DIV_MASK 0x3FF
+#define PPLL_FB3_DIV_MASK 0x7FF
+#define PPLL_POST3_DIV_MASK 0x70000
+#define PPLL_ATOMIC_UPDATE_R 0x8000
+#define PPLL_ATOMIC_UPDATE_W 0x8000
+#define MEM_CFG_TYPE_MASK 0x3
+#define XCLK_SRC_SEL_MASK 0x7
+#define XPLL_FB_DIV_MASK 0xFF00
+#define X_MPLL_REF_DIV_MASK 0xFF
+
+/* CRTC control values (CRTC_GEN_CNTL) */
+#define CRTC_CSYNC_EN 0x00000010
+
+#define CRTC_PIX_WIDTH_MASK 0x00000700
+#define CRTC_PIX_WIDTH_4BPP 0x00000100
+#define CRTC_PIX_WIDTH_8BPP 0x00000200
+#define CRTC_PIX_WIDTH_15BPP 0x00000300
+#define CRTC_PIX_WIDTH_16BPP 0x00000400
+#define CRTC_PIX_WIDTH_24BPP 0x00000500
+#define CRTC_PIX_WIDTH_32BPP 0x00000600
+
+/* DAC_CNTL bit constants */
+#define DAC_8BIT_EN 0x00000100
+
+/* GEN_RESET_CNTL bit constants */
+#define SOFT_RESET_GUI 0x00000001
+#define SOFT_RESET_VCLK 0x00000100
+#define SOFT_RESET_PCLK 0x00000200
+#define SOFT_RESET_ECP 0x00000400
+#define SOFT_RESET_DISPENG_XCLK 0x00000800
+
+/* PC_GUI_CTLSTAT bit constants */
+#define PC_BUSY_INIT 0x10000000
+#define PC_BUSY_GUI 0x20000000
+#define PC_BUSY_NGUI 0x40000000
+#define PC_BUSY 0x80000000
+
+#define BUS_MASTER_DIS 0x00000040
+#define PM4_BUFFER_CNTL_NONPM4 0x00000000
+
+/* DP_GUI_MASTER_CNTL bit constants */
+#define GMC_SRC_PITCH_OFFSET_DEFAULT 0x00000000
+#define GMC_DST_PITCH_OFFSET_DEFAULT 0x00000000
+#define GMC_SRC_CLIP_DEFAULT 0x00000000
+#define GMC_DST_CLIP_DEFAULT 0x00000000
+#define GMC_BRUSH_SOLIDCOLOR 0x000000d0
+#define GMC_SRC_DSTCOLOR 0x00003000
+#define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000
+#define GMC_DP_SRC_RECT 0x02000000
+#define GMC_3D_FCN_EN_CLR 0x00000000
+#define GMC_AUX_CLIP_CLEAR 0x20000000
+#define GMC_DST_CLR_CMP_FCN_CLEAR 0x10000000
+#define GMC_WRITE_MASK_SET 0x40000000
+#define GMC_DP_CONVERSION_TEMP_6500 0x00000000
+
+/* DP_GUI_MASTER_CNTL ROP3 named constants */
+#define ROP3_PATCOPY 0x00f00000
+#define ROP3_SRCCOPY 0x00cc0000 // S
+
+#define SRC_DSTCOLOR 0x00030000
+
+/* DP_CNTL bit constants */
+#define DST_X_RIGHT_TO_LEFT 0x00000000
+#define DST_X_LEFT_TO_RIGHT 0x00000001
+#define DST_Y_BOTTOM_TO_TOP 0x00000000
+#define DST_Y_TOP_TO_BOTTOM 0x00000002
+#define DST_X_MAJOR 0x00000000
+#define DST_Y_MAJOR 0x00000004
+#define DST_X_TILE 0x00000008
+#define DST_Y_TILE 0x00000010
+#define DST_LAST_PEL 0x00000020
+#define DST_TRAIL_X_RIGHT_TO_LEFT 0x00000000
+#define DST_TRAIL_X_LEFT_TO_RIGHT 0x00000040
+#define DST_TRAP_FILL_RIGHT_TO_LEFT 0x00000000
+#define DST_TRAP_FILL_LEFT_TO_RIGHT 0x00000080
+#define DST_BRES_SIGN 0x00000100
+#define DST_HOST_BIG_ENDIAN_EN 0x00000200
+#define DST_POLYLINE_NONLAST 0x00008000
+#define DST_RASTER_STALL 0x00010000
+#define DST_POLY_EDGE 0x00040000
+
+/* DP_MIX bit constants */
+#define DP_SRC_RECT 0x00000200
+#define DP_SRC_HOST 0x00000300
+#define DP_SRC_HOST_BYTEALIGN 0x00000400
+
+#endif /* REG_RAGE128_H */
--- /dev/null
+/* $Id: aty128fb.c,v 1.1 1999/10/12 11:00:43 geert Exp $
+ * linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128
+ *
+ * Copyright (C) Summer 1999, Anthony Tong <atong@uiuc.edu>
+ *
+ * Brad Douglas <brad@neruo.com>
+ * - x86 support
+ * - MTRR
+ * - Probe ROM for PLL
+ *
+ * Based off of Geert's atyfb.c and vfb.c.
+ *
+ * TODO:
+ * - panning
+ * - fix 15/16 bpp on big endian arch's
+ * - monitor sensing (DDC)
+ * - other platform support (only ppc/x86 supported)
+ * - PPLL_REF_DIV & XTALIN calculation
+ * - determine MCLK from previous hardware setting
+ */
+
+/*
+ * A special note of gratitude to ATI's devrel for providing documentation,
+ * example code and hardware. Thanks Nitya. -atong
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PPC)
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <linux/nvram.h>
+#include <video/macmodes.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "aty128.h"
+
+#undef DEBUG
+#undef CONFIG_MTRR /* not ready? */
+
+#ifdef DEBUG
+#define DBG(x) printk(KERN_INFO "aty128fb: %s\n",(x));
+#else
+#define DBG(x)
+#endif
+
+static char *aty128fb_name = "ATY Rage128";
+
+static struct fb_var_screeninfo default_var = {
+ /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
+
+#pragma pack(1)
+typedef struct {
+ u8 clock_chip_type;
+ u8 struct_size;
+ u8 accelerator_entry;
+ u8 VGA_entry;
+ u16 VGA_table_offset;
+ u16 POST_table_offset;
+ u16 XCLK;
+ u16 MCLK;
+ u8 num_PLL_blocks;
+ u8 size_PLL_blocks;
+ u16 PCLK_ref_freq;
+ u16 PCLK_ref_divider;
+ u32 PCLK_min_freq;
+ u32 PCLK_max_freq;
+ u16 MCLK_ref_freq;
+ u16 MCLK_ref_divider;
+ u32 MCLK_min_freq;
+ u32 MCLK_max_freq;
+ u16 XCLK_ref_freq;
+ u16 XCLK_ref_divider;
+ u32 XCLK_min_freq;
+ u32 XCLK_max_freq;
+} PLL_BLOCK;
+#pragma pack()
+
+struct aty128_meminfo {
+ u8 ML;
+ u8 MB;
+ u8 Trcd;
+ u8 Trp;
+ u8 Twr;
+ u8 CL;
+ u8 Tr2w;
+ u8 LoopLatency;
+ u8 DspOn;
+ u8 Rloop;
+};
+
+const struct aty128_meminfo sdr_128 = { 4, 4, 3, 3, 1, 3, 1, 16, 30, 16 };
+const struct aty128_meminfo sdr_64 = { 4, 8, 3, 3, 1, 3, 1, 17, 46, 17 };
+const struct aty128_meminfo sdr_sgram = { 4, 4, 1, 2, 1, 2, 1, 16, 24, 16 };
+const struct aty128_meminfo ddr_sgram = { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16 };
+
+static int currcon = 0;
+static char fontname[40] __initdata = { 0 };
+
+#if defined(CONFIG_PPC)
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
+#endif
+
+#if defined(CONFIG_MTRR)
+static int mtrr = 1;
+#endif
+
+struct aty128_constants {
+ u32 dotclock;
+ u32 ppll_min;
+ u32 ppll_max;
+ u32 ref_divider;
+ u32 xclk;
+ u32 fifo_width;
+ u32 fifo_depth;
+};
+
+struct aty128_crtc {
+ u32 gen_cntl;
+ u32 ext_cntl;
+ u32 h_total, h_sync_strt_wid;
+ u32 v_total, v_sync_strt_wid;
+ u32 pitch;
+ u32 offset, offset_cntl;
+ u32 vxres, vyres;
+ u32 bpp;
+};
+
+struct aty128_pll {
+ u32 post_divider;
+ u32 feedback_divider;
+ u32 vclk;
+};
+
+struct aty128_ddafifo {
+ u32 dda_config;
+ u32 dda_on_off;
+};
+
+/* register values for a specific mode */
+struct aty128fb_par {
+ struct aty128_crtc crtc;
+ struct aty128_pll pll;
+ struct aty128_ddafifo fifo_reg;
+ u32 accel_flags;
+};
+
+struct fb_info_aty128 {
+ struct fb_info fb_info;
+ struct aty128_constants constants;
+ unsigned long regbase_phys, regbase;
+ unsigned long frame_buffer_phys, frame_buffer;
+ const struct aty128_meminfo *mem;
+ u32 vram_size;
+ u32 BIOS_SEG;
+#ifdef CONFIG_MTRR
+ struct { int vram; int vram_valid; } mtrr;
+#endif
+ struct aty128fb_par default_par, current_par;
+ struct display disp;
+ struct { u8 red, green, blue, pad; } palette[256];
+ union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+ } fbcon_cmap;
+ int blitter_may_be_busy;
+};
+
+#define round_div(n, d) ((n+(d/2))/d)
+
+ /*
+ * Interface used by the world
+ */
+
+int aty128fb_setup(char *options);
+
+static int aty128fb_open(struct fb_info *info, int user);
+static int aty128fb_release(struct fb_info *info, int user);
+static int aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int aty128fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int aty128fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+
+ /*
+ * Interface to the low level console driver
+ */
+
+void aty128fb_init(void);
+#ifdef CONFIG_FB_OF
+void aty128fb_of_init(struct device_node *dp);
+#endif
+static int aty128fbcon_switch(int con, struct fb_info *info);
+static void aty128fbcon_blank(int blank, struct fb_info *info);
+
+
+ /*
+ * Internal routines
+ */
+
+static void aty128_encode_fix(struct fb_fix_screeninfo *fix,
+ struct aty128fb_par *par,
+ const struct fb_info_aty128 *info);
+static void aty128_set_disp(struct display *disp,
+ struct fb_info_aty128 *info, int bpp, int accel);
+static int aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info);
+static int aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+static void aty128pci_probe(void);
+static int aty128find_ROM(struct fb_info_aty128 *info);
+static void aty128_timings(struct fb_info_aty128 *info);
+static void aty128_get_pllinfo(struct fb_info_aty128 *info);
+static void aty128_reset_engine(const struct fb_info_aty128 *info);
+static void aty128_flush_pixel_cache(const struct fb_info_aty128 *info);
+static void wait_for_fifo(u16 entries, const struct fb_info_aty128 *info);
+static void wait_for_idle(const struct fb_info_aty128 *info);
+static u32 bpp_to_depth(u32 bpp);
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_aty128_8;
+#endif
+
+
+static struct fb_ops aty128fb_ops = {
+ aty128fb_open, aty128fb_release, aty128fb_get_fix,
+ aty128fb_get_var, aty128fb_set_var, aty128fb_get_cmap,
+ aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl
+};
+
+
+ /*
+ * Functions to read from/write to the mmio registers
+ * - endian conversions may possibly be avoided by flipping CONFIG_CNTL
+ * or using the other register aperture? TODO.
+ */
+static inline u32
+_aty_ld_le32(volatile unsigned int regindex,
+ const struct fb_info_aty128 *info)
+{
+ unsigned long temp;
+ u32 val;
+
+#if defined(__powerpc__)
+ eieio();
+ temp = info->regbase;
+ asm("lwbrx %0,%1,%2" : "=b"(val) : "b" (regindex), "b" (temp));
+#elif defined(__sparc_v9__)
+ temp = info->regbase + regindex;
+ asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
+#else
+ temp = info->regbase+regindex;
+ val = le32_to_cpu(*((volatile u32 *)(temp)));
+#endif
+ return val;
+}
+
+static inline void
+_aty_st_le32(volatile unsigned int regindex, u32 val,
+ const struct fb_info_aty128 *info)
+{
+ unsigned long temp;
+
+#if defined(__powerpc__)
+ eieio();
+ temp = info->regbase;
+ asm("stwbrx %0,%1,%2" : : "b" (val), "b" (regindex), "b" (temp) :
+ "memory");
+#elif defined(__sparc_v9__)
+ temp = info->regbase + regindex;
+ asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
+#else
+ temp = info->regbase+regindex;
+ *((volatile u32 *)(temp)) = cpu_to_le32(val);
+#endif
+}
+
+static inline u8
+_aty_ld_8(volatile unsigned int regindex,
+ const struct fb_info_aty128 *info)
+{
+#if defined(__powerpc__)
+ eieio();
+#endif
+ return *(volatile u8 *)(info->regbase+regindex);
+}
+
+static inline void
+_aty_st_8(volatile unsigned int regindex, u8 val,
+ const struct fb_info_aty128 *info)
+{
+#if defined(__powerpc__)
+ eieio();
+#endif
+ *(volatile u8 *)(info->regbase+regindex) = val;
+}
+
+#define aty_ld_le32(regindex) _aty_ld_le32(regindex, info)
+#define aty_st_le32(regindex, val) _aty_st_le32(regindex, val, info)
+#define aty_ld_8(regindex) _aty_ld_8(regindex, info)
+#define aty_st_8(regindex, val) _aty_st_8(regindex, val, info)
+
+ /*
+ * Functions to read from/write to the pll registers
+ */
+
+#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, info)
+#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, info)
+
+static u32
+_aty_ld_pll(unsigned int pll_index,
+ const struct fb_info_aty128 *info)
+{
+ aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F);
+ return aty_ld_le32(CLOCK_CNTL_DATA);
+}
+
+static void
+_aty_st_pll(unsigned int pll_index, u32 val,
+ const struct fb_info_aty128 *info)
+{
+ aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN);
+ aty_st_le32(CLOCK_CNTL_DATA, val);
+}
+
+/* return true when the PLL has completed an atomic update */
+static int
+aty_pll_readupdate(const struct fb_info_aty128 *info)
+{
+ return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
+}
+
+static void
+aty_pll_wait_readupdate(const struct fb_info_aty128 *info)
+{
+ unsigned long timeout = jiffies + HZ/100; // should be more than enough
+ int reset = 1;
+
+ while (time_before(jiffies, timeout))
+ if (aty_pll_readupdate(info)) {
+ reset = 0;
+ break;
+ }
+
+#ifdef DEBUG
+ if (reset) /* reset engine?? */
+ printk(KERN_ERR "aty128fb: PLL write timeout!");
+#endif
+}
+
+/* tell PLL to update */
+static void
+aty_pll_writeupdate(const struct fb_info_aty128 *info)
+{
+ aty_pll_wait_readupdate(info);
+
+ aty_st_pll(PPLL_REF_DIV,
+ aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);
+}
+
+
+/* write to the scratch register to test r/w functionality */
+static u32
+register_test(const struct fb_info_aty128 *info)
+{
+ u32 val, flag = 0;
+
+ val = aty_ld_le32(BIOS_0_SCRATCH);
+
+ aty_st_le32(BIOS_0_SCRATCH, 0x55555555);
+ if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) {
+ aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA);
+
+ if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA)
+ flag = 1;
+ }
+
+ aty_st_le32(BIOS_0_SCRATCH, val); // restore value
+ return flag;
+}
+
+
+ /*
+ * Accelerator functions
+ */
+static void
+wait_for_idle(const struct fb_info_aty128 *info)
+{
+ unsigned long timeout = jiffies + HZ/20;
+ int reset = 1;
+
+ wait_for_fifo(64, info);
+
+ while (time_before(jiffies, timeout))
+ if ((aty_ld_le32(GUI_STAT) & GUI_ACTIVE) != ENGINE_IDLE) {
+ reset = 0;
+ break;
+ }
+
+ if (reset)
+ aty128_reset_engine(info);
+}
+
+
+static void
+wait_for_fifo(u16 entries, const struct fb_info_aty128 *info)
+{
+ unsigned long timeout = jiffies + HZ/20;
+ int reset = 1;
+
+ while (time_before(jiffies, timeout))
+ if ((aty_ld_le32(GUI_STAT) & 0x00000FFF) < entries) {
+ reset = 0;
+ break;
+ }
+
+ if (reset)
+ aty128_reset_engine(info);
+}
+
+
+static void
+aty128_flush_pixel_cache(const struct fb_info_aty128 *info)
+{
+ int i = 16384;
+
+ aty_st_le32(PC_NGUI_CTLSTAT, aty_ld_le32(PC_NGUI_CTLSTAT) | 0x000000ff);
+
+ while (i && (aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY))
+ i--;
+}
+
+
+static void
+aty128_reset_engine(const struct fb_info_aty128 *info)
+{
+ u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
+
+ aty128_flush_pixel_cache(info);
+
+ clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX);
+ mclk_cntl = aty_ld_pll(MCLK_CNTL);
+
+ aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000);
+
+ gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL);
+ aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI);
+ aty_ld_le32(GEN_RESET_CNTL);
+ aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI));
+ aty_ld_le32(GEN_RESET_CNTL);
+
+ aty_st_pll(MCLK_CNTL, mclk_cntl);
+ aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index);
+ aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl);
+
+ /* use old pio mode */
+ aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4);
+
+#ifdef DEBUG
+ printk("aty128fb: engine reset\n");
+#endif
+}
+
+
+static void
+aty128_init_engine(const struct aty128fb_par *par,
+ const struct fb_info_aty128 *info)
+{
+ u32 temp;
+ aty_st_le32(SCALE_3D_CNTL, 0x00000000);
+
+ aty128_reset_engine(info);
+
+ temp = par->crtc.pitch; /* fix this up */
+ if (par->crtc.bpp == 24) {
+ temp = temp * 3;
+ }
+
+ /* setup engine offset registers */
+ wait_for_fifo(4, info);
+ aty_st_le32(DEFAULT_OFFSET, 0x00000000);
+
+ /* setup engine pitch registers */
+ aty_st_le32(DEFAULT_PITCH, temp);
+
+ /* set the default scissor register to max dimensions */
+ wait_for_fifo(1, info);
+ aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);
+
+ /* set the drawing controls registers */
+ wait_for_fifo(1, info);
+ aty_st_le32(DP_GUI_MASTER_CNTL,
+ GMC_SRC_PITCH_OFFSET_DEFAULT |
+ GMC_DST_PITCH_OFFSET_DEFAULT |
+ GMC_SRC_CLIP_DEFAULT |
+ GMC_DST_CLIP_DEFAULT |
+ GMC_BRUSH_SOLIDCOLOR |
+ (bpp_to_depth(par->crtc.bpp) << 8) |
+ GMC_SRC_DSTCOLOR |
+ GMC_BYTE_ORDER_MSB_TO_LSB |
+ GMC_DP_CONVERSION_TEMP_6500 |
+ ROP3_PATCOPY |
+ GMC_DP_SRC_RECT |
+ GMC_3D_FCN_EN_CLR |
+ GMC_DST_CLR_CMP_FCN_CLEAR |
+ GMC_AUX_CLIP_CLEAR |
+ GMC_WRITE_MASK_SET);
+ wait_for_fifo(8, info);
+
+ /* clear the line drawing registers */
+ aty_st_le32(DST_BRES_ERR, 0);
+ aty_st_le32(DST_BRES_INC, 0);
+ aty_st_le32(DST_BRES_DEC, 0);
+
+ /* set brush color registers */
+ aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF);
+ aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000);
+
+ /* set source color registers */
+ aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF);
+ aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000);
+
+ /* default write mask */
+ aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);
+
+ /* Wait for all the writes to be completed before returning */
+ wait_for_idle(info);
+}
+
+
+ /*
+ * CRTC programming
+ */
+
+/* convert bpp values to their register representation */
+static u32
+bpp_to_depth(u32 bpp)
+{
+ if (bpp <= 8)
+ return 2;
+ else if (bpp <= 15)
+ return 3;
+ else if (bpp <= 16)
+#if 0 /* force 15bpp */
+ return 4;
+#else
+ return 3;
+#endif
+ else if (bpp <= 24)
+ return 5;
+ else if (bpp <= 32)
+ return 6;
+
+ return -EINVAL;
+}
+
+
+static void
+aty128_set_crtc(const struct aty128_crtc *crtc,
+ const struct fb_info_aty128 *info)
+{
+ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
+ // aty_st_le32(CRTC_EXT_CNTL, crtc->ext_cntl);
+ aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
+ aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid);
+ aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total);
+ aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid);
+ aty_st_le32(CRTC_PITCH, crtc->pitch);
+ aty_st_le32(CRTC_OFFSET, crtc->offset);
+ aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl);
+}
+
+
+static int
+aty128_var_to_crtc(const struct fb_var_screeninfo *var,
+ struct aty128_crtc *crtc,
+ const struct fb_info_aty128 *info)
+{
+ u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+ u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+ u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol;
+ u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+ u32 depth;
+ u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 };
+
+ /* input */
+ xres = var->xres;
+ yres = var->yres;
+ vxres = var->xres_virtual;
+ vyres = var->yres_virtual;
+ xoffset = var->xoffset;
+ yoffset = var->yoffset;
+ bpp = var->bits_per_pixel;
+ left = var->left_margin;
+ right = var->right_margin;
+ upper = var->upper_margin;
+ lower = var->lower_margin;
+ hslen = var->hsync_len;
+ vslen = var->vsync_len;
+ sync = var->sync;
+ vmode = var->vmode;
+
+ /* check for mode eligibility */
+
+ /* accept only non interlaced modes */
+ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+
+ /* convert (and round up) and validate */
+ xres = (xres + 7) & ~7;
+ xoffset = (xoffset + 7) & ~7;
+
+ if (vxres < xres + xoffset)
+ vxres = xres + xoffset;
+
+ if (vyres < yres + yoffset)
+ vyres = yres + yoffset;
+
+ if (bpp <= 8)
+ bpp = 8;
+ else if (bpp <= 16)
+ bpp = 16;
+ else if (bpp <= 32)
+ bpp = 32;
+
+ if (vxres * vyres * (bpp/8) > info->vram_size)
+ return -EINVAL;
+
+ h_disp = xres / 8 - 1;
+ h_total = (xres + right + hslen + left) / 8 - 1;
+
+ v_disp = yres - 1;
+ v_total = yres + upper + vslen + lower - 1;
+
+ h_sync_wid = hslen / 8;
+ if (h_sync_wid == 0)
+ h_sync_wid = 1;
+ else if (h_sync_wid > 0x3f)
+ h_sync_wid = 0x3f;
+
+ h_sync_strt = (xres + right - 8) + hsync_strt_pix[bpp/8];
+
+ v_disp = yres - 1;
+ v_sync_wid = vslen;
+ if (v_sync_wid == 0)
+ v_sync_wid = 1;
+ else if (v_sync_wid > 0x1f)
+ v_sync_wid = 0x1f;
+
+ v_sync_strt = yres + lower - 1;
+
+ h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : (1 << 23);
+ v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : (1 << 23);
+
+ depth = bpp_to_depth(bpp);
+ c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
+
+ crtc->gen_cntl = 0x03000000 | c_sync | depth << 8;
+
+ crtc->h_total = (h_disp << 16) | (h_total & 0x0000FFFF);
+ crtc->v_total = (v_disp << 16) | (v_total & 0x0000FFFF);
+
+ crtc->h_sync_strt_wid = (h_sync_wid << 16) | (h_sync_strt) | h_sync_pol;
+ crtc->v_sync_strt_wid = (v_sync_wid << 16) | (v_sync_strt) | v_sync_pol;
+
+ crtc->pitch = xres / 8;
+
+ crtc->offset = 0;
+ crtc->offset_cntl = 0;
+
+ crtc->vxres = vxres;
+ crtc->vyres = vyres;
+ crtc->bpp = bpp;
+
+ return 0;
+}
+
+
+static int
+aty128_crtc_to_var(const struct aty128_crtc *crtc,
+ struct fb_var_screeninfo *var)
+{
+#ifdef notyet /* xoffset and yoffset are not correctly calculated */
+ u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+ u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+ u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+ u32 pix_width;
+
+ h_total = crtc->h_total & 0x1ff;
+ h_disp = (crtc->h_total>>16) & 0xff;
+ h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
+ ((crtc->h_sync_strt_wid>>4) & 0x100);
+ h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
+ h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
+ h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
+ v_total = crtc->v_total & 0x7ff;
+ v_disp = (crtc->v_total>>16) & 0x7ff;
+ v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+ v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+ v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+ c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
+ pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+ xres = (h_disp+1)*8;
+ yres = v_disp+1;
+ left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+ right = (h_sync_strt-h_disp)*8+h_sync_dly;
+ hslen = h_sync_wid*8;
+ upper = v_total-v_sync_strt-v_sync_wid;
+ lower = v_sync_strt-v_disp;
+ vslen = v_sync_wid;
+ sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+ (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
+ (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
+
+ switch (pix_width) {
+#if 0
+ case CRTC_PIX_WIDTH_4BPP:
+ bpp = 4;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_8BPP:
+ bpp = 8;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_15BPP:
+ bpp = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_16BPP:
+ bpp = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_24BPP:
+ bpp = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_32BPP:
+ bpp = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ default:
+ printk(KERN_ERR "Invalid pixel width\n");
+ }
+
+//Godda do math for xoffset and yoffset: does not exist in crtc
+ var->xres = xres;
+ var->yres = yres;
+ var->xres_virtual = crtc->vxres;
+ var->yres_virtual = crtc->vyres;
+ var->bits_per_pixel = bpp;
+ var->xoffset = crtc->xoffset;
+ var->yoffset = crtc->yoffset;
+ var->left_margin = left;
+ var->right_margin = right;
+ var->upper_margin = upper;
+ var->lower_margin = lower;
+ var->hsync_len = hslen;
+ var->vsync_len = vslen;
+ var->sync = sync;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+#endif /* notyet */
+ return 0;
+}
+
+static int
+aty128_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
+{
+ /* fill in pixel info */
+ switch (bpp) {
+ case 8:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 15:
+ var->bits_per_pixel = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ break;
+ case 16:
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ }
+
+ return 0;
+}
+
+
+static void
+aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info)
+{
+ int div3;
+ unsigned char post_conv[] = /* register values for post dividers */
+ { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
+
+ /* select PPLL_DIV_3 */
+ aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
+
+ /* reset ppll */
+ aty_st_pll(PPLL_CNTL,
+ aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
+
+ div3 = aty_ld_pll(PPLL_DIV_3);
+
+ div3 &= ~PPLL_FB3_DIV_MASK;
+ div3 |= pll->feedback_divider;
+
+ div3 &= ~PPLL_POST3_DIV_MASK;
+ div3 |= post_conv[pll->post_divider] << 16;
+
+ /* write feedback and post dividers */
+ aty_st_pll(PPLL_DIV_3, div3);
+ aty_pll_writeupdate(info);
+ aty_pll_wait_readupdate(info);
+
+ aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */
+
+ aty_pll_writeupdate(info);
+
+ /* clear the reset, just in case */
+ aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);
+}
+
+
+static int
+aty128_var_to_pll(u32 vclk_per, struct aty128_pll *pll,
+ const struct fb_info_aty128 *info)
+{
+ const struct aty128_constants c = info->constants;
+ unsigned char post_dividers [] = {1,2,4,8,3,6,12};
+ u32 output_freq, vclk;
+ int i;
+ u32 n, d;
+
+ vclk = 100000000 / vclk_per; /* convert units to 10 kHz */
+
+ /* adjust pixel clock if necessary */
+ if (vclk > c.ppll_max)
+ vclk = c.ppll_max;
+ if (vclk * 12 < c.ppll_min)
+ vclk = c.ppll_min;
+
+ /* now, find an acceptable divider */
+ for (i = 0; i < sizeof(post_dividers); i++) {
+ output_freq = post_dividers[i] * vclk;
+ if (output_freq >= c.ppll_min && output_freq <= c.ppll_max)
+ break;
+ }
+ pll->post_divider = post_dividers[i];
+
+ /* calculate feedback divider */
+ n = c.ref_divider * output_freq;
+ d = c.dotclock;
+ pll->feedback_divider = round_div(n, d);
+
+ pll->vclk = vclk;
+#ifdef DEBUG
+ printk("post %x feedback %x vlck %x output %x\n",
+ pll->post_divider, pll->feedback_divider, vclk, output_freq);
+#endif
+
+ return 0;
+}
+
+
+static int
+aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
+{
+ /* TODO */
+ return 0;
+}
+
+
+static void
+aty128_set_fifo(const struct aty128_ddafifo *dsp,
+ const struct fb_info_aty128 *info)
+{
+ aty_st_le32(DDA_CONFIG, dsp->dda_config);
+ aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
+}
+
+
+static int
+aty128_ddafifo(struct aty128_ddafifo *dsp,
+ const struct aty128_pll *pll,
+ u32 bpp,
+ const struct fb_info_aty128 *info)
+{
+ const struct aty128_meminfo *m = info->mem;
+ u32 xclk = info->constants.xclk;
+ u32 fifo_width = info->constants.fifo_width;
+ u32 fifo_depth = info->constants.fifo_depth;
+ s32 x, b, p, ron, roff;
+ u32 n, d;
+
+ if (bpp == 15)
+ bpp = 16;
+
+ n = xclk * fifo_width;
+ d = pll->vclk*bpp;
+ x = round_div(n, d);
+
+ ron = 4 * m->MB +
+ 3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +
+ 2 * m->Trp +
+ m->Twr +
+ m->CL +
+ m->Tr2w +
+ x;
+
+#ifdef DEBUG
+ printk("x %x\n", x);
+#endif
+ b = 0;
+ while (x) {
+ x >>= 1;
+ b++;
+ }
+ p = b + 1;
+
+ ron <<= (11 - p);
+
+ n <<= (11 - p);
+ x = round_div(n, d);
+ roff = x * (fifo_depth - 4);
+ if ((ron + m->Rloop) >= roff) {
+ printk("Mode out of range\n");
+ return -EINVAL;
+ }
+
+#ifdef DEBUG
+ printk("p: %x rloop: %x x: %x ron: %x roff: %x\n", p, m->Rloop, x,
+ ron, roff);
+#endif
+ dsp->dda_config = p << 16 | m->Rloop << 20 | x;
+ dsp->dda_on_off = ron << 16 | roff;
+
+ return 0;
+}
+
+
+/*
+ * This actually sets the video mode.
+ */
+static void
+aty128_set_par(struct aty128fb_par *par,
+ struct fb_info_aty128 *info)
+{
+ u32 config;
+
+ info->current_par = *par;
+
+ /* clear all registers that may interfere with mode setting */
+ aty_st_le32(OVR_CLR, 0);
+ aty_st_le32(OVR_WID_LEFT_RIGHT, 0);
+ aty_st_le32(OVR_WID_TOP_BOTTOM, 0);
+ aty_st_le32(OV0_SCALE_CNTL, 0);
+ aty_st_le32(MPP_TB_CONFIG, 0);
+ aty_st_le32(MPP_GP_CONFIG, 0);
+ aty_st_le32(SUBPIC_CNTL, 0);
+ aty_st_le32(VIPH_CONTROL, 0);
+ aty_st_le32(I2C_CNTL_1, 0);
+ aty_st_le32(GEN_INT_CNTL, 0); /* turn off interrupts */
+ aty_st_le32(CAP0_TRIG_CNTL, 0);
+ aty_st_le32(CAP1_TRIG_CNTL, 0);
+
+ aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */
+
+ aty128_set_crtc(&par->crtc, info);
+ aty128_set_pll(&par->pll, info);
+ aty128_set_fifo(&par->fifo_reg, info);
+
+ config = aty_ld_le32(CONFIG_CNTL) & ~3;
+
+#if defined(__BIG_ENDIAN)
+ if (par->crtc.bpp >= 24)
+ config |= 2; /* make aperture do 32 byte swapping */
+ else if (par->crtc.bpp > 8)
+ config |= 1; /* make aperture do 16 byte swapping */
+#endif
+
+ aty_st_le32(CONFIG_CNTL, config);
+
+ aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */
+}
+
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int aty128fb_open(struct fb_info *info, int user)
+{
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+
+static int aty128fb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+
+static int
+aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par,
+ const struct fb_info_aty128 *info)
+{
+ int err;
+
+ if ((err = aty128_var_to_crtc(var, &(par->crtc), info)))
+ return err;
+
+ if ((err = aty128_var_to_pll(var->pixclock, &(par->pll), info)))
+ return err;
+
+ if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info)))
+ return err;
+
+ if (var->accel_flags & FB_ACCELF_TEXT)
+ par->accel_flags = FB_ACCELF_TEXT;
+ else
+ par->accel_flags = 0;
+
+ return 0;
+}
+
+
+static int
+aty128_encode_var(struct fb_var_screeninfo *var,
+ const struct aty128fb_par *par,
+ const struct fb_info_aty128 *info)
+{
+ int err;
+
+ //memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+ /* XXX aty128_*_to_var() aren't fully implemented! */
+ if ((err = aty128_crtc_to_var(&par->crtc, var)))
+ return err;
+
+ if ((err = aty128_pll_to_var(&par->pll, var)))
+ return err;
+
+ if ((err = aty128_bpp_to_var(var->bits_per_pixel, var)))
+ return err;
+
+ var->height = -1;
+ var->width = -1;
+ var->accel_flags = par->accel_flags;
+
+ return 0;
+}
+
+
+ /*
+ * Get the User Defined Part of the Display
+ */
+
+static int
+aty128fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+ const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+
+ if (con == -1)
+ aty128_encode_var(var, &info->default_par, info);
+ else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+
+ /*
+ * Set the User Defined Part of the Display
+ */
+
+static int
+aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+ struct aty128fb_par par;
+ struct display *display;
+ int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
+ int accel, err;
+
+ display = (con >= 0) ? &fb_display[con] : fb->disp;
+
+ if ((err = aty128_decode_var(var, &par, info)))
+ return err;
+
+ aty128_encode_var(var, &par, info);
+
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return 0;
+
+ oldxres = display->var.xres;
+ oldyres = display->var.yres;
+ oldvxres = display->var.xres_virtual;
+ oldvyres = display->var.yres_virtual;
+ oldbpp = display->var.bits_per_pixel;
+ oldaccel = display->var.accel_flags;
+ display->var = *var;
+ if (oldxres != var->xres || oldyres != var->yres ||
+ oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
+
+ struct fb_fix_screeninfo fix;
+ aty128_encode_fix(&fix, &par, info);
+ display->screen_base = (char *) info->frame_buffer;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+
+ accel = var->accel_flags & FB_ACCELF_TEXT;
+ aty128_set_disp(display, info, var->bits_per_pixel, accel);
+
+#if 0 /* acceleration is not ready */
+ if (accel)
+ display->scrollmode = 0;
+ else
+#endif
+ display->scrollmode = SCROLL_YREDRAW;
+
+ if (info->fb_info.changevar)
+ (*info->fb_info.changevar)(con);
+ }
+
+ if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con)
+ aty128_set_par(&par, info);
+
+ if (oldbpp != var->bits_per_pixel) {
+ if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+ return err;
+ do_install_cmap(con, &info->fb_info);
+ }
+
+ return 0;
+}
+
+
+static void
+aty128_set_disp(struct display *disp,
+ struct fb_info_aty128 *info, int bpp, int accel)
+{
+ switch (bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ disp->dispsw = &fbcon_cfb16;
+ disp->dispsw_data = info->fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ disp->dispsw = &fbcon_cfb24;
+ disp->dispsw_data = info->fbcon_cmap.cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ disp->dispsw = &fbcon_cfb32;
+ disp->dispsw_data = info->fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ disp->dispsw = &fbcon_dummy;
+ }
+}
+
+
+static void
+aty128_encode_fix(struct fb_fix_screeninfo *fix,
+ struct aty128fb_par *par,
+ const struct fb_info_aty128 *info)
+{
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ strcpy(fix->id, aty128fb_name);
+ fix->smem_start = (long) info->frame_buffer_phys;
+ fix->smem_len = info->vram_size;
+
+ fix->mmio_start = (long) info->regbase_phys;
+ fix->mmio_len = 0x1fff;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+ fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+
+ fix->xpanstep = 8;
+ fix->ypanstep = 1;
+
+ fix->accel = FB_ACCEL_ATI_RAGE128;
+ return;
+}
+
+
+ /*
+ * Get the Fixed Part of the Display
+ */
+static int
+aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+ const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+ struct aty128fb_par par;
+
+ if (con == -1)
+ par = info->default_par;
+ else
+ aty128_decode_var(&fb_display[con].var, &par, info);
+
+ aty128_encode_fix(fix, &par, info);
+ return 0;
+}
+
+
+ /*
+ * Pan or Wrap the Display
+ *
+ * Not supported (yet!)
+ */
+static int
+aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (var->xoffset != 0 || var->yoffset != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+ /*
+ * Get the Colormap
+ */
+
+static int
+aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ if (!info->display_fg ||
+ con == info->display_fg->vc_num) /* current console ? */
+ return fb_get_cmap(cmap, kspc, aty128_getcolreg, info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else {
+ int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32;
+ fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+ }
+ return 0;
+}
+
+ /*
+ * Set the Colormap
+ */
+
+static int
+aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+ struct display *disp;
+
+ if (con >= 0)
+ disp = &fb_display[con];
+ else
+ disp = info->disp;
+ if (!disp->cmap.len) { /* no colormap allocated? */
+ int size = (disp->var.bits_per_pixel <= 16) ? 256 : 32;
+ if ((err = fb_alloc_cmap(&disp->cmap, size, 0)))
+ return err;
+ }
+ if (!info->display_fg || con == info->display_fg->vc_num)
+/* current console? */
+ return fb_set_cmap(cmap, kspc, aty128_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+
+ /*
+ * Virtual Frame Buffer Specific ioctls
+ */
+
+static int
+aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+
+int __init
+aty128fb_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return 0;
+
+ for (this_opt = strtok(options, ","); this_opt;
+ this_opt = strtok(NULL, ",")) {
+ if (!strncmp(this_opt, "font:", 5)) {
+ char *p;
+ int i;
+
+ p = this_opt +5;
+ for (i = 0; i < sizeof(fontname) - 1; i++)
+ if (!*p || *p == ' ' || *p == ',')
+ break;
+ memcpy(fontname, this_opt + 5, i);
+ fontname[i] = 0;
+ }
+#if defined(CONFIG_PPC)
+ if (!strncmp(this_opt, "vmode:", 6)) {
+ unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+ if (vmode > 0 && vmode <= VMODE_MAX)
+ default_vmode = vmode;
+ } else if (!strncmp(this_opt, "cmode:", 6)) {
+ unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+ switch (cmode) {
+ case 0:
+ case 8:
+ default_cmode = CMODE_8;
+ break;
+ case 15:
+ case 16:
+ default_cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ default_cmode = CMODE_32;
+ break;
+ }
+ }
+#endif
+#ifdef CONFIG_MTRR
+ if(mtrr) {
+ ACCESS_FBINFO(mtrr.vram) =
+ mtrr_add(video_base_phys, ACCESS_FBINFO(video.len),
+ MTRR_TYPE_WRCOMB, 1);
+ ACCESS_FBINFO(mtrr.valid_vram) = 1;
+ printk(KERN_INFO "aty128fb: MTRR set to ON\n");
+ }
+#endif
+ }
+ return 0;
+}
+
+
+ /*
+ * Initialisation
+ */
+
+static int
+aty128_init(struct fb_info_aty128 *info, const char *name)
+{
+ struct fb_var_screeninfo var;
+ u32 dac;
+ int j, k;
+ u8 chip_rev;
+
+ if (!register_test(info)) {
+ printk("Can't write to video registers\n");
+ return 0;
+ }
+
+ if (!info->vram_size) /* may have already been probed */
+ info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+ chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
+
+ /* TODO be more verbose */
+ printk("aty128fb: Rage128 [rev 0x%x] ", chip_rev);
+
+ if (info->vram_size % (1024 * 1024) == 0)
+ printk("%dM ", info->vram_size / (1024*1024));
+ else
+ printk("%dk ", info->vram_size / 1024);
+
+ var = default_var;
+
+#ifdef CONFIG_PMAC
+
+ if (default_vmode == VMODE_NVRAM) {
+#ifdef CONFIG_NVRAM
+ default_vmode = nvram_read_byte(NV_VMODE);
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+#endif /* CONFIG_NVRAM */
+ default_vmode = VMODE_CHOOSE;
+ }
+
+ if (default_cmode == CMODE_NVRAM) {
+#ifdef CONFIG_NVRAM
+ default_cmode = nvram_read_byte(NV_CMODE);
+ if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+#endif /* CONFIG_NVRAM */
+ default_vmode = VMODE_CHOOSE;
+ }
+
+ if (default_vmode != VMODE_CHOOSE &&
+ mac_vmode_to_var(default_vmode, default_cmode, &var))
+ var = default_var;
+
+#endif /* CONFIG_PMAC */
+
+ if (aty128_decode_var(&var, &info->default_par, info)) {
+ printk("Cannot set default mode.\n");
+ return 0;
+ }
+
+ /* fill in info */
+ strcpy(info->fb_info.modename, aty128fb_name);
+ info->fb_info.node = -1;
+ info->fb_info.fbops = &aty128fb_ops;
+ info->fb_info.disp = &info->disp;
+ strcpy(info->fb_info.fontname, fontname);
+ info->fb_info.changevar = NULL;
+ info->fb_info.switch_con = &aty128fbcon_switch;
+ info->fb_info.blank = &aty128fbcon_blank;
+ info->fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+ for (j = 0; j < 16; j++) {
+ k = color_table[j];
+ info->palette[j].red = default_red[k];
+ info->palette[j].green = default_grn[k];
+ info->palette[j].blue = default_blu[k];
+ }
+
+ dac = aty_ld_le32(DAC_CNTL) & 15; /* preserve lower three bits */
+ dac |= DAC_8BIT_EN; /* set 8 bit dac */
+ dac |= (0xFF << 24); /* set DAC mask */
+ aty_st_le32(DAC_CNTL, dac);
+
+ /* turn off bus mastering, just in case */
+ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS);
+
+ aty128fb_set_var(&var, -1, &info->fb_info);
+ aty128_init_engine(&info->default_par, info);
+
+ printk("\n");
+ if (register_framebuffer(&info->fb_info) < 0)
+ return 0;
+
+ printk("fb%d: %s frame buffer device on %s\n",
+ GET_FB_IDX(info->fb_info.node), aty128fb_name, name);
+
+ return 1; /* success! */
+}
+
+
+void __init
+aty128fb_init(void)
+{
+#if defined(CONFIG_FB_OF)
+/* let offb handle init */
+#elif defined (CONFIG_PCI)
+ aty128pci_probe();
+#endif
+}
+
+
+void
+aty128pci_probe(void)
+{
+ struct pci_dev *pdev;
+ struct fb_info_aty128 *info;
+ unsigned long fb_addr, reg_addr;
+ u16 tmp;
+
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
+ (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+ struct resource *rp;
+
+ /* FIXME add other known R128 device ID's */
+ switch (pdev->device) {
+ case 0x5245:
+ case 0x5246:
+ case 0x524B:
+ case 0x524C:
+ break;
+ default:
+ continue;
+ }
+
+ rp = &pdev->resource[0];
+ fb_addr = rp->start;
+ if (!fb_addr)
+ continue;
+ fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ rp = &pdev->resource[2];
+ reg_addr = rp->start;
+ if (!reg_addr)
+ continue;
+ reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
+ if (!info) {
+ printk("aty128fb: can't alloc fb_info_aty128\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct fb_info_aty128));
+
+ info->regbase_phys = reg_addr;
+ info->regbase = (unsigned long) ioremap(reg_addr, 0x1FFF);
+
+ if (!info->regbase) {
+ kfree(info);
+ return;
+ }
+
+ info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+ info->frame_buffer = fb_addr;
+ info->frame_buffer = (unsigned long)
+ ioremap(fb_addr, info->vram_size);
+
+ if (!info->frame_buffer) {
+ kfree(info);
+ return;
+ }
+
+ pci_read_config_word(pdev, PCI_COMMAND, &tmp);
+ if (!(tmp & PCI_COMMAND_MEMORY)) {
+ tmp |= PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, tmp);
+ }
+
+#if defined(CONFIG_PPC)
+ aty128_timings(info);
+#else
+ if (!aty128find_ROM(info)) {
+ printk("Rage128 BIOS not located. Guessing...\n");
+ aty128_timings(info);
+ }
+ else
+ aty128_get_pllinfo(info);
+#endif
+
+ if (!aty128_init(info, "PCI")) {
+ kfree(info);
+ return;
+ }
+ }
+ }
+}
+
+
+static int
+aty128find_ROM(struct fb_info_aty128 *info)
+{
+ u32 segstart;
+ char *rom_base;
+ char *rom_base1;
+ char *rom;
+ int stage;
+ int i;
+ char aty_rom_sig[] = "761295520";
+ char R128_sig[] = "R128";
+ int flag = 0;
+DBG("E aty128find_ROM");
+
+ for (segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000) {
+ stage = 1;
+
+ rom_base = (char *) ioremap(segstart, 0x1000);
+ rom_base1 = (char *) (rom_base+1);
+
+ if ((*rom_base == 0x55) && (((*rom_base1) & 0xff) == 0xaa)) {
+ stage = 2;
+ }
+
+ if (stage != 2) {
+ iounmap(rom_base);
+ continue;
+ }
+ rom = rom_base;
+
+ for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) {
+ if (aty_rom_sig[0] == *rom) {
+ if (strncmp(aty_rom_sig, rom, strlen(aty_rom_sig)) == 0) {
+ stage = 3;
+ }
+ }
+ rom++;
+ }
+ if (stage != 3) {
+ iounmap(rom_base);
+ continue;
+ }
+ rom = rom_base;
+
+ for (i = 0; (i < 512) && (stage != 4); i++) {
+ if (R128_sig[0] == *rom) {
+ if (strncmp(R128_sig, rom, strlen(R128_sig)) == 0) {
+ stage = 4;
+ }
+ }
+ rom++;
+ }
+ if (stage != 4) {
+ iounmap(rom_base);
+ continue;
+ }
+
+ printk("Rage128 BIOS located at segment %4.4X\n", (u32)rom_base);
+ info->BIOS_SEG = (u32)rom_base;
+ flag = 1;
+
+ break;
+ }
+DBG("L aty128find_ROM");
+ return (flag);
+}
+
+
+static void
+aty128_get_pllinfo(struct fb_info_aty128 *info)
+{
+ u32 bios_header;
+ u32 *header_ptr;
+ u16 bios_header_offset, pll_info_offset;
+ PLL_BLOCK pll;
+DBG("E aty128_get_pllinfo");
+
+ bios_header = info->BIOS_SEG + 0x48L;
+ header_ptr = (u32 *)bios_header;
+
+ bios_header_offset = (u16)*header_ptr;
+ bios_header = info->BIOS_SEG + (u32)bios_header_offset;
+ bios_header += 0x30;
+
+ header_ptr = (u32 *)bios_header;
+ pll_info_offset = (u16)*header_ptr;
+ header_ptr = (u32 *)(info->BIOS_SEG + (u32)pll_info_offset);
+
+ memcpy(&pll, header_ptr, 50);
+
+ info->constants.ppll_max = pll.PCLK_max_freq;
+ info->constants.ppll_min = pll.PCLK_min_freq;
+ info->constants.xclk = (u32)pll.XCLK;
+ info->constants.ref_divider = (u32)pll.PCLK_ref_divider;
+ info->constants.dotclock = (u32)pll.PCLK_ref_freq;
+
+ info->constants.fifo_width = 128;
+ info->constants.fifo_depth = 32;
+
+ switch(aty_ld_le32(MEM_CNTL) & 0x03) {
+ case 0:
+ info->mem = &sdr_128;
+ break;
+ case 1:
+ info->mem = &sdr_sgram;
+ break;
+ case 2:
+ info->mem = &ddr_sgram;
+ break;
+ default:
+ info->mem = &sdr_sgram;
+ }
+
+DBG("L aty128get_pllinfo");
+ return;
+}
+
+
+#ifdef CONFIG_FB_OF
+void
+aty128fb_of_init(struct device_node *dp)
+{
+ unsigned long addr, reg_addr, fb_addr;
+ struct fb_info_aty128 *info;
+ u8 bus, devfn;
+ u16 cmd;
+
+ switch (dp->n_addrs) {
+ case 3:
+ fb_addr = dp->addrs[0].address;
+ reg_addr = dp->addrs[2].address;
+ break;
+ default:
+ printk("aty128fb: TODO unexpected addresses\n");
+ return;
+ }
+
+ addr = (unsigned long) ioremap(reg_addr, 0x1FFF);
+ if (!addr) {
+ printk("aty128fb: can't map memory registers\n");
+ return;
+ }
+
+ info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
+ if (!info) {
+ printk("aty128fb: can't alloc fb_info_aty128\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct fb_info_aty128));
+
+ info->regbase_phys = reg_addr;
+ info->regbase = addr;
+
+ /* enabled memory-space accesses using config-space command register */
+ if (pci_device_loc(dp, &bus, &devfn) == 0) {
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MEMORY)) {
+ cmd |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ }
+ }
+
+ info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+ info->frame_buffer_phys = fb_addr;
+ info->frame_buffer = (unsigned long) ioremap(fb_addr, info->vram_size);
+
+ /*
+ * TODO find OF values/hints.
+ *
+ * If we are booted from BootX, the MacOS ATI driver will likely have
+ * left useful tidbits in the DeviceRegistry.
+ */
+
+ if (!info->frame_buffer) {
+ printk("aty128fb: can't map frame buffer\n");
+ return;
+ }
+
+ aty128_timings(info);
+
+ if (!aty128_init(info, dp->full_name)) {
+ kfree(info);
+ return;
+ }
+}
+#endif
+
+
+/* fill in known card constants if pll_block is not available */
+static void
+aty128_timings(struct fb_info_aty128 *info)
+{
+ /* TODO make an attempt at probing */
+
+ info->constants.dotclock = 2950;
+
+ /* from documentation */
+ info->constants.ppll_min = 12500;
+ info->constants.ppll_max = 25000; /* 23000 on some cards? */
+
+#if 1
+ /* XXX TODO. Calculate properly. Fix OF's pll ideas. */
+ info->constants.ref_divider = 0x3b;
+ aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
+ aty_pll_writeupdate(info);
+
+ aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+ aty_pll_writeupdate(info);
+#else
+ info->constants.ref_divider = aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
+
+ /* TODO. Calculate */
+ info->constants.xclk = 0x1d4d; /* same as mclk */
+
+ info->constants.fifo_width = 128;
+ info->constants.fifo_depth = 32;
+
+ switch (aty_ld_le32(MEM_CNTL) & 0x3) {
+ case 0:
+ info->mem = &sdr_128;
+ break;
+ case 1:
+ info->mem = &sdr_sgram;
+ break;
+ case 2:
+ info->mem = &ddr_sgram;
+ break;
+ default:
+ info->mem = &sdr_sgram;
+ }
+}
+
+
+static int
+aty128fbcon_switch(int con, struct fb_info *fb)
+{
+ currcon = con;
+
+ /* Do we have to save the colormap? */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, aty128_getcolreg, fb);
+
+#if 1
+ aty128fb_set_var(&fb_display[con].var, con, fb);
+#else
+{
+ struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb;
+ struct aty128fb_par par;
+
+ aty128_decode_var(&fb_display[con].var, &par, info);
+ aty128_set_par(&par, info);
+ aty128_set_disp(&fb_display[con], info,
+ fb_display[con].var.bits_per_pixel);
+
+ do_install_cmap(con, fb);
+}
+#endif
+
+ return 1;
+}
+
+
+ /*
+ * Blank the display.
+ */
+
+static void
+aty128fbcon_blank(int blank, struct fb_info *fb)
+{
+ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+ u8 state = 0;
+
+ if (blank & VESA_VSYNC_SUSPEND)
+ state |= 2;
+ if (blank & VESA_HSYNC_SUSPEND)
+ state |= 1;
+ if (blank & VESA_POWERDOWN)
+ state |= 4;
+
+ aty_st_8(CRTC_EXT_CNTL+1, state);
+}
+
+
+ /*
+ * Read a single color register and split it into
+ * colors/transparent. Return != 0 for invalid regno.
+ */
+static int
+aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *fb)
+{
+ struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb;
+
+ if (regno > 255)
+ return 1;
+
+ *red = (info->palette[regno].red<<8) | info->palette[regno].red;
+ *green = (info->palette[regno].green<<8) | info->palette[regno].green;
+ *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue;
+ *transp = 0;
+ return 0;
+}
+
+
+ /*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+static int
+aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb;
+ u32 col;
+
+ if (regno > 255)
+ return 1;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ info->palette[regno].red = red;
+ info->palette[regno].green = green;
+ info->palette[regno].blue = blue;
+
+ aty_st_8(PALETTE_INDEX, regno);
+ col = red << 16 | green << 8 | blue;
+ aty_st_le32(PALETTE_DATA, col);
+
+ if (regno < 16)
+ switch (info->current_par.crtc.bpp) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
+ regno;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) |
+ regno;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ {
+ u32 i;
+ i = (regno << 8) | regno;
+ info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
+ }
+ break;
+#endif
+ }
+ return 0;
+}
+
+
+static void
+do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, aty128_setcolreg, info);
+ else {
+ int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 16;
+ fb_set_cmap(fb_default_cmap(size), 1, aty128_setcolreg, info);
+ }
+}
+
+
+ /*
+ * Accelerated functions
+ */
+
+static void
+aty128_rectdraw(s16 x, s16 y, u16 width, u16 height,
+ struct fb_info_aty128 *info)
+{
+ /* perform rectangle fill */
+ wait_for_fifo(2, info);
+ aty_st_le32(DST_Y_X, (y << 16) | x);
+ aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
+}
+
+
+static void
+aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
+ u_int width, u_int height,
+ struct fb_info_aty128 *info)
+{
+ u32 direction = DST_LAST_PEL;
+ u32 pitch_value;
+
+ if (!width || !height)
+ return;
+
+ pitch_value = info->current_par.crtc.vxres;
+ if (info->current_par.crtc.bpp == 24) {
+ /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+ /* horizontal coordinates and widths must be adjusted */
+ pitch_value *= 3;
+ srcx *= 3;
+ dstx *= 3;
+ width *= 3;
+ }
+
+ if (srcy < dsty) {
+ dsty += height - 1;
+ srcy += height - 1;
+ } else
+ direction |= DST_Y_TOP_TO_BOTTOM;
+
+ if (srcx < dstx) {
+ dstx += width - 1;
+ srcx += width - 1;
+ } else
+ direction |= DST_X_LEFT_TO_RIGHT;
+
+ wait_for_fifo(4, info);
+ aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
+ aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
+ aty_st_le32(DP_CNTL, direction);
+ aty_st_le32(DP_DATATYPE, aty_ld_le32(DP_DATATYPE) | SRC_DSTCOLOR);
+ aty128_rectdraw(dstx, dsty, width, height, info);
+}
+
+static void
+fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ sx *= fontwidth(p);
+ sy *= fontheight(p);
+ dx *= fontwidth(p);
+ dy *= fontheight(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+
+ aty128_rectcopy(sx, sy, dx, dy, width, height,
+ (struct fb_info_aty128 *)p->fb_info);
+}
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_aty128_8 = {
+ fbcon_cfb8_setup, fbcon_aty128_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc,
+ fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#if defined(MODULE) && defined(DEBUG)
+int
+init_module(void)
+{
+ aty128pci_probe();
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+/* XXX unregister! */
+}
+#endif /* MODULE */
}
dsp_precision -= 5;
/* fifo_off<<6 */
- fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(1<<6);
+ fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6);
if (info->total_vram > 1*1024*1024) {
if (info->ram_type >= SDRAM) {
if (xclks_per_row >= (page_size<<11))
fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
else
- fifo_on = (3*page_size)<<6;
+ fifo_on = (3*page_size+2)<<6;
dsp_xclks_per_row = xclks_per_row>>dsp_precision;
dsp_on = fifo_on>>dsp_precision;
// useful at blank = 1 too (saves battery, extends backlight life)
if (blank) {
pmu_enable_backlight(0);
+ /* get the palette from the chip */
+ for (i = 0; i < 256; ++i) {
+ out_8(p->io_base + 0x3c7, i);
+ udelay(1);
+ p->palette[i].red = in_8(p->io_base + 0x3c9);
+ p->palette[i].green = in_8(p->io_base + 0x3c9);
+ p->palette[i].blue = in_8(p->io_base + 0x3c9);
+ }
for (i = 0; i < 256; ++i) {
out_8(p->io_base + 0x3c8, i);
udelay(1);
}
} else {
pmu_enable_backlight(1);
- do_install_cmap(currcon, info);
+ for (i = 0; i < 256; ++i) {
+ out_8(p->io_base + 0x3c8, i);
+ udelay(1);
+ out_8(p->io_base + 0x3c9, p->palette[i].red);
+ out_8(p->io_base + 0x3c9, p->palette[i].green);
+ out_8(p->io_base + 0x3c9, p->palette[i].blue);
+ }
}
}
for (p = all_chips; p != NULL; p = p->next) {
int nb = p->var.yres * p->fix.line_length;
- int i;
switch (when) {
case PBOOK_SLEEP_NOW:
chipsfb_blank(1, (struct fb_info *)p);
- /* get the palette from the chip, Xpmac seems
- to set it directly in the chip */
- for (i = 0; i < 256; ++i) {
- out_8(p->io_base + 0x3c8, i);
- udelay(1);
- p->palette[i].red = in_8(p->io_base + 0x3c9);
- p->palette[i].green = in_8(p->io_base + 0x3c9);
- p->palette[i].blue = in_8(p->io_base + 0x3c9);
- }
p->save_framebuffer = vmalloc(nb);
if (p->save_framebuffer)
memcpy(p->save_framebuffer,
#ifdef CONFIG_FB_ATY
extern void atyfb_of_init(struct device_node *dp);
#endif /* CONFIG_FB_ATY */
+#ifdef CONFIG_FB_ATY128
+extern void aty128fb_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_ATY */
#ifdef CONFIG_FB_S3TRIO
extern void s3triofb_init_of(struct device_node *dp);
#endif /* CONFIG_FB_S3TRIO */
dp->addrs[0].size = 0x01000000;
}
}
+
+ /*
+ * The LTPro on the Lombard powerbook has no addresses
+ * on the display nodes, they are on their parent.
+ */
+ if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,264LTPro")) {
+ int na;
+ unsigned int *ap = (unsigned int *)
+ get_property(dp, "AAPL,address", &na);
+ if (ap != 0)
+ for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
+ if (*ap <= addr && addr < *ap + 0x1000000)
+ goto foundit;
+ }
+
/*
* See if the display address is in one of the address
* ranges for this display.
break;
}
if (i < dp->n_addrs) {
+ foundit:
printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
macos_display = dp;
break;
static int __init offb_init_driver(struct device_node *dp)
{
+#ifdef CONFIG_FB_ATY128
+ if (!strncmp(dp->name, "ATY,Rage128", 11)) {
+ aty128fb_of_init(dp);
+ return 1;
+ }
+#endif
#ifdef CONFIG_FB_ATY
if (!strncmp(dp->name, "ATY", 3)) {
atyfb_of_init(dp);
*/
int d_invalidate(struct dentry * dentry)
{
+ /*
+ * If it's already been dropped, return OK.
+ */
+ if (list_empty(&dentry->d_hash))
+ return 0;
/*
* Check whether to do a partial shrink_dcache
* to get rid of unused child entries.
mpnt->vm_offset = 0;
mpnt->vm_file = NULL;
mpnt->vm_private_data = (void *) 0;
+ vmlist_modify_lock(current->mm);
insert_vm_struct(current->mm, mpnt);
+ vmlist_modify_unlock(current->mm);
current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
}
permission(bprm->dentry->d_inode,MAY_READ))
current->dumpable = 0;
+ /* An exec changes our domain. We are no longer part of the thread
+ group */
+
+ current->self_exec_id++;
+
flush_signal_handlers(current);
flush_old_files(current->files);
* by hand after calling find_inode now! This simplify iunique and won't
* add any additional branch in the common code.
*/
-static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
{
struct list_head *tmp;
struct inode * inode;
continue;
if (inode->i_ino != ino)
continue;
+ if (find_actor && !find_actor(inode, ino, opaque))
+ continue;
break;
}
return inode;
* We no longer cache the sb_flags in i_flags - see fs.h
* -- rmk@arm.uk.linux.org
*/
-static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
{
struct inode * inode;
spin_lock(&inode_lock);
/* We released the lock, so.. */
- old = find_inode(sb, ino, head);
+ old = find_inode(sb, ino, head, find_actor, opaque);
if (!old)
{
list_add(&inode->i_list, &inode_in_use);
retry:
if (counter > max_reserved) {
head = inode_hashtable + hash(sb,counter);
- inode = find_inode(sb, res = counter++, head);
+ inode = find_inode(sb, res = counter++, head, NULL, NULL);
if (!inode) {
spin_unlock(&inode_lock);
return res;
return inode;
}
-struct inode *iget(struct super_block *sb, unsigned long ino)
+struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
{
struct list_head * head = inode_hashtable + hash(sb,ino);
struct inode * inode;
spin_lock(&inode_lock);
- inode = find_inode(sb, ino, head);
+ inode = find_inode(sb, ino, head, find_actor, opaque);
if (inode) {
__iget(inode);
spin_unlock(&inode_lock);
* get_new_inode() will do the right thing, re-trying the search
* in case it had to block at any point.
*/
- return get_new_inode(sb, ino, head);
+ return get_new_inode(sb, ino, head, find_actor, opaque);
}
void insert_inode_hash(struct inode *inode)
*/
#define DATA_BUFFER_USED(bh) \
- (atomic_read(&bh->b_count) || buffer_locked(bh))
+ (atomic_read(&bh->b_count) > 1 || buffer_locked(bh))
/*
* The functions for minix V1 fs truncation.
* If mtime is close to present time, we revalidate
* more often.
*/
+#define NFS_REVALIDATE_NEGATIVE (1 * HZ)
static inline int nfs_neg_need_reval(struct dentry *dentry)
{
- unsigned long timeout = 30 * HZ;
- long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+ struct inode *dir = dentry->d_parent->d_inode;
+ unsigned long timeout = NFS_ATTRTIMEO(dir);
+ long diff = CURRENT_TIME - dir->i_mtime;
- if (diff < 5*60)
- timeout = 1 * HZ;
+ if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
+ timeout = NFS_REVALIDATE_NEGATIVE;
return time_after(jiffies, dentry->d_time + timeout);
}
goto out_bad;
}
- if (IS_ROOT(dentry))
- goto out_valid;
-
if (!nfs_dentry_force_reval(dentry, flags))
goto out_valid;
+ if (IS_ROOT(dentry)) {
+ __nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ goto out_valid_renew;
+ }
+
/*
* Do a new lookup and check the dentry attributes.
*/
goto out_bad;
/* Inode number matches? */
- if (fattr.fileid != inode->i_ino)
+ if (NFS_FSID(inode) != fattr.fsid ||
+ NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
/* Filehandle matches? */
- if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
- if (!list_empty(&dentry->d_subdirs))
- shrink_dcache_parent(dentry);
- if (dentry->d_count < 2)
- goto out_bad;
- }
+ if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
+ goto out_bad;
/* Ok, remeber that we successfully checked it.. */
- nfs_renew_times(dentry);
nfs_refresh_inode(inode, &fattr);
+ out_valid_renew:
+ nfs_renew_times(dentry);
out_valid:
return 1;
out_bad:
+ d_drop(dentry);
+ if (!list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
/* Purge readdir caches. */
if (dentry->d_parent->d_inode) {
- invalidate_inode_pages(dentry->d_parent->d_inode);
- nfs_flush_dircache(dentry->d_parent->d_inode);
- }
- if (inode && S_ISDIR(inode->i_mode)) {
- invalidate_inode_pages(inode);
- nfs_flush_dircache(inode);
+ nfs_zap_caches(dentry->d_parent->d_inode);
+ NFS_CACHEINV(dentry->d_parent->d_inode);
}
return 0;
}
dentry->d_name.name, error);
}
-#ifdef NFS_PARANOIA
- /*
- * Sanity check: if the dentry has been unhashed and the
- * inode still has users, we could have problems ...
- */
- if (list_empty(&dentry->d_hash) && dentry->d_inode) {
- struct inode *inode = dentry->d_inode;
- int max_count = (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink);
- if (inode->i_count > max_count) {
-printk("nfs_dentry_delete: %s/%s: ino=%ld, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
- }
- }
-#endif
}
static kmem_cache_t *nfs_fh_cachep;
error = -EACCES;
inode = nfs_fhget(dentry, &fhandle, &fattr);
if (inode) {
-#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
-printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-show_dentry(&inode->i_dentry);
-}
-#endif
no_entry:
d_add(dentry, inode);
nfs_renew_times(dentry);
inode = nfs_fhget(dentry, fhandle, fattr);
if (inode) {
-#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
-printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-show_dentry(&inode->i_dentry);
-}
-#endif
d_instantiate(dentry, inode);
nfs_renew_times(dentry);
error = 0;
static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- struct nfs_sattr sattr;
+ struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- sattr.mode = mode;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_mode = mode;
+ attr.ia_valid = ATTR_MODE;
/*
* Invalidate the dir cache before the operation to avoid a race.
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
+ dentry->d_name.name, &attr, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
int error;
- struct nfs_sattr sattr;
+ struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- sattr.mode = mode;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- if (S_ISCHR(mode) || S_ISBLK(mode))
- sattr.size = rdev; /* get out your barf bag */
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_mode = mode;
+ attr.ia_valid = ATTR_MODE;
+ /* FIXME: move this to a special nfs_proc_mknod() */
+ if (S_ISCHR(mode) || S_ISBLK(mode)) {
+ attr.ia_size = rdev; /* get out your barf bag */
+ attr.ia_valid |= ATTR_SIZE;
+ }
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
+ dentry->d_name.name, &attr, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- struct nfs_sattr sattr;
+ struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- sattr.mode = mode | S_IFDIR;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_valid = ATTR_MODE;
+ attr.ia_mode = mode | S_IFDIR;
/*
* Always drop the dentry, we can't always depend on
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
+ dentry->d_name.name, &attr, &fhandle, &fattr);
if (!error)
dir->i_nlink++;
return error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
-#ifdef NFS_PARANOIA
-if (dentry->d_inode->i_count > 1)
-printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-dentry->d_inode->i_count, dentry->d_inode->i_nlink);
-#endif
-
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
#endif
goto out;
}
-#ifdef NFS_PARANOIA
-if (inode && inode->i_count > inode->i_nlink)
-printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_count, inode->i_nlink);
-#endif
/*
* Unhash the dentry while we remove the file ...
*/
static int
nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- struct nfs_sattr sattr;
+ struct iattr attr;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
* Fill in the sattr for the call.
* Note: SunOS 4.1.2 crashes if the mode isn't initialized!
*/
- sattr.mode = S_IFLNK | S_IRWXUGO;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_valid = ATTR_MODE;
+ attr.ia_mode = S_IFLNK | S_IRWXUGO;
/*
* Drop the dentry in advance to force a new lookup.
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, symname, &sattr);
+ dentry->d_name.name, symname, &attr);
if (!error) {
nfs_renew_times(dentry->d_parent);
} else if (error == -EEXIST) {
* To prevent any new references to the target during the rename,
* we unhash the dentry and free the inode in advance.
*/
-#ifdef NFS_PARANOIA
-if (new_inode &&
- new_inode->i_count > (S_ISDIR(new_inode->i_mode) ? 1 : new_inode->i_nlink))
-printk("nfs_rename: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_inode->i_count, new_inode->i_nlink);
-#endif
if (!list_empty(&new_dentry->d_hash)) {
d_drop(new_dentry);
rehash = update;
#define NFS_PARANOIA 1
static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
-static void nfs_zap_caches(struct inode *);
+void nfs_zap_caches(struct inode *);
static void nfs_invalidate_inode(struct inode *);
static void nfs_read_inode(struct inode *);
inode->i_mode = 0;
inode->i_rdev = 0;
inode->i_op = NULL;
+ NFS_FILEID(inode) = 0;
+ NFS_FSID(inode) = 0;
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_count, !list_empty(&dentry->d_hash));
+ if (!list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
if (!dentry->d_count) {
dget(dentry);
d_drop(dentry);
dput(dentry);
goto restart;
}
- if (!list_empty(&dentry->d_hash))
+ if (list_empty(&dentry->d_hash))
unhashed++;
}
return unhashed;
/*
* Invalidate the local caches
*/
-static void
+void
nfs_zap_caches(struct inode *inode)
{
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
* do this once. (We don't allow inodes to change types.)
*/
if (inode->i_mode == 0) {
+ NFS_FILEID(inode) = fattr->fileid;
+ NFS_FSID(inode) = fattr->fsid;
inode->i_mode = fattr->mode;
if (S_ISREG(inode->i_mode))
inode->i_op = &nfs_file_inode_operations;
nfs_refresh_inode(inode, fattr);
}
+/*
+ * In NFSv3 we can have 64bit inode numbers. In order to support
+ * this, and re-exported directories (also seen in NFSv2)
+ * we are forced to allow 2 different inodes to have the same
+ * i_ino.
+ */
+static int
+nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
+{
+ struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+ if (NFS_FSID(inode) != fattr->fsid)
+ return 0;
+ if (NFS_FILEID(inode) != fattr->fileid)
+ return 0;
+ return 1;
+}
+
+static int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+{
+ int unhashed;
+ int is_stale = 0;
+
+ if (inode->i_mode &&
+ (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+ is_stale = 1;
+
+ if (is_bad_inode(inode))
+ is_stale = 1;
+
+ /*
+ * If the inode seems stale, free up cached dentries.
+ */
+ unhashed = nfs_free_dentries(inode);
+
+ /* Assume we're holding an i_count
+ *
+ * NB: sockets sometimes have volatile file handles
+ * don't invalidate their inodes even if all dentries are
+ * unhashed.
+ */
+ if (unhashed && inode->i_count == unhashed + 1
+ && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
+ is_stale = 1;
+
+ return is_stale;
+}
+
/*
* This is our own version of iget that looks up inodes by file handle
* instead of inode number. We use this technique instead of using
static struct inode *
__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
{
- struct inode *inode;
- int max_count, stale_inode, unhashed = 0;
+ struct inode *inode = NULL;
+ unsigned long ino;
-retry:
- inode = iget(sb, fattr->fileid);
- if (!inode)
+ if (!fattr->nlink) {
+ printk("NFS: Buggy server - nlink == 0!\n");
goto out_no_inode;
- /* N.B. This should be impossible ... */
- if (inode->i_ino != fattr->fileid)
- goto out_bad_id;
+ }
- /*
- * Check for busy inodes, and attempt to get rid of any
- * unused local references. If successful, we release the
- * inode and try again.
- *
- * Note that the busy test uses the values in the fattr,
- * as the inode may have become a different object.
- * (We can probably handle modes changes here, too.)
- */
- stale_inode = inode->i_mode &&
- ((fattr->mode ^ inode->i_mode) & S_IFMT);
- stale_inode |= inode->i_count && inode->i_count == unhashed;
- max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
- if (stale_inode || inode->i_count > max_count + unhashed) {
- dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
- inode->i_ino, inode->i_count, inode->i_nlink);
- unhashed = nfs_free_dentries(inode);
- if (stale_inode || inode->i_count > max_count + unhashed) {
- printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
- inode->i_ino, inode->i_count);
- if (!list_empty(&inode->i_dentry)) {
- struct dentry *dentry;
- dentry = list_entry(inode->i_dentry.next,
- struct dentry, d_alias);
- printk("__nfs_fhget: killing %s/%s filehandle\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name);
- memset(dentry->d_fsdata, 0,
- sizeof(struct nfs_fh));
- }
- remove_inode_hash(inode);
- nfs_invalidate_inode(inode);
- unhashed = 0;
- }
+ ino = fattr->fileid;
+
+ while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
+
+ /*
+ * Check for busy inodes, and attempt to get rid of any
+ * unused local references. If successful, we release the
+ * inode and try again.
+ *
+ * Note that the busy test uses the values in the fattr,
+ * as the inode may have become a different object.
+ * (We can probably handle modes changes here, too.)
+ */
+ if (!nfs_inode_is_stale(inode,fattr))
+ break;
+
+ dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+ inode->i_ino, inode->i_count);
+ nfs_zap_caches(inode);
+ remove_inode_hash(inode);
iput(inode);
- goto retry;
}
+
+ if (!inode)
+ goto out_no_inode;
+
nfs_fill_inode(inode, fattr);
dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino, inode->i_count);
out_no_inode:
printk("__nfs_fhget: iget failed\n");
goto out;
-out_bad_id:
- printk("__nfs_fhget: unexpected inode from iget\n");
- goto out;
}
int
nfs_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
- int error;
- struct nfs_sattr sattr;
struct nfs_fattr fattr;
+ int error;
/*
* Make sure the inode is up-to-date.
goto out;
}
- sattr.mode = (u32) -1;
- if (attr->ia_valid & ATTR_MODE)
- sattr.mode = attr->ia_mode;
-
- sattr.uid = (u32) -1;
- if (attr->ia_valid & ATTR_UID)
- sattr.uid = attr->ia_uid;
-
- sattr.gid = (u32) -1;
- if (attr->ia_valid & ATTR_GID)
- sattr.gid = attr->ia_gid;
-
- sattr.size = (u32) -1;
- if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
- sattr.size = attr->ia_size;
-
- sattr.mtime.seconds = sattr.mtime.useconds = (u32) -1;
- if (attr->ia_valid & ATTR_MTIME) {
- sattr.mtime.seconds = attr->ia_mtime;
- sattr.mtime.useconds = 0;
- }
-
- sattr.atime.seconds = sattr.atime.useconds = (u32) -1;
- if (attr->ia_valid & ATTR_ATIME) {
- sattr.atime.seconds = attr->ia_atime;
- sattr.atime.useconds = 0;
- }
+ if (!S_ISREG(inode->i_mode))
+ attr->ia_valid &= ~ATTR_SIZE;
error = nfs_wb_all(inode);
if (error)
goto out;
error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
- &sattr, &fattr);
+ &fattr, attr);
if (error)
goto out;
/*
* If we changed the size or mtime, update the inode
* now to avoid invalidating the page cache.
*/
- if (sattr.size != (u32) -1) {
- if (sattr.size != fattr.size)
- printk("nfs_notify_change: sattr=%d, fattr=%d??\n",
- sattr.size, fattr.size);
- inode->i_size = sattr.size;
+ if (attr->ia_valid & ATTR_SIZE) {
+ if (attr->ia_size != fattr.size)
+ printk("nfs_notify_change: attr=%ld, fattr=%d??\n",
+ attr->ia_size, fattr.size);
+ inode->i_size = attr->ia_size;
inode->i_mtime = fattr.mtime.seconds;
}
- if (sattr.mtime.seconds != (u32) -1)
+ if (attr->ia_valid & ATTR_MTIME)
inode->i_mtime = fattr.mtime.seconds;
error = nfs_refresh_inode(inode, &fattr);
out:
return error;
}
+/*
+ * Wait for the inode to get unlocked.
+ * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
+ */
+int
+nfs_wait_on_inode(struct inode *inode, int flag)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+ int intr, error = 0;
+
+ intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR;
+ add_wait_queue(&inode->i_wait, &wait);
+ for (;;) {
+ set_task_state(tsk, (intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE));
+ error = 0;
+ if (!(NFS_FLAGS(inode) & flag))
+ break;
+ error = -ERESTARTSYS;
+ if (intr && signalled())
+ break;
+ schedule();
+ }
+ set_task_state(tsk, TASK_RUNNING);
+ remove_wait_queue(&inode->i_wait, &wait);
+ return error;
+}
+
/*
* Externally visible revalidation function
*/
* the cached attributes have to be refreshed.
*/
int
-_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
int status = 0;
dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino);
+
+ if (!inode || is_bad_inode(inode))
+ return -ESTALE;
+
+ while (NFS_REVALIDATING(inode)) {
+ status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
+ if (status < 0)
+ return status;
+ if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
+ return 0;
+ }
+ NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
+
status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
if (status) {
int error;
dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
out:
+ NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
+ wake_up(&inode->i_wait);
return status;
}
return p;
}
+
+#define SATTR(p, attr, flag, field) \
+ *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
+xdr_encode_sattr(u32 *p, struct iattr *attr)
{
- *p++ = htonl(sattr->mode);
- *p++ = htonl(sattr->uid);
- *p++ = htonl(sattr->gid);
- *p++ = htonl(sattr->size);
- *p++ = htonl(sattr->atime.seconds);
- *p++ = htonl(sattr->atime.useconds);
- *p++ = htonl(sattr->mtime.seconds);
- *p++ = htonl(sattr->mtime.useconds);
- return p;
+ SATTR(p, attr, ATTR_MODE, ia_mode);
+ SATTR(p, attr, ATTR_UID, ia_uid);
+ SATTR(p, attr, ATTR_GID, ia_gid);
+ SATTR(p, attr, ATTR_SIZE, ia_size);
+
+ if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
+ *p++ = htonl(attr->ia_atime);
+ *p++ = 0;
+ } else {
+ *p++ = ~(u32) 0;
+ *p++ = ~(u32) 0;
+ }
+
+ if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
+ *p++ = htonl(attr->ia_mtime);
+ *p++ = 0;
+ } else {
+ *p++ = ~(u32) 0;
+ *p++ = ~(u32) 0;
+ }
+ return p;
}
+#undef SATTR
/*
* NFS encode functions
int
nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_sattr *sattr, struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr, struct iattr *sattr)
{
struct nfs_sattrargs arg = { fhandle, sattr };
int status;
int
nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_sattr *sattr,
+ const char *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { dir, name, sattr };
int
nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
const char *name, const char *path,
- struct nfs_sattr *sattr)
+ struct iattr *sattr)
{
struct nfs_symlinkargs arg = { dir, name, path, sattr };
int status;
int
nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_sattr *sattr,
+ const char *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { dir, name, sattr };
*
* aeb@cwi.nl : /proc/partitions
*
+ *
* Alan Cox : security fixes.
* <Alan.Cox@linux.org>
*
*
* Gerhard Wichert : added BIGMEM support
* Siemens AG <Gerhard.Wichert@pdb.siemens.de>
- *
- * Chuck Lever : safe handling of task_struct
- * <cel@monkey.org>
- *
- * Andrea Arcangeli : SMP race/security fixes.
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/signal.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
return result;
}
} while (addr & ~PAGE_MASK);
- kunmap(addr-1, KM_READ);
+ kunmap(addr, KM_READ);
}
return result;
}
{
struct task_struct *p;
struct mm_struct *mm = NULL;
-
- /* need kernel lock to avoid the tsk->mm to go away under us */
- lock_kernel();
+
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
if (p)
if (mm)
atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock);
- unlock_kernel();
return mm;
}
+
static int get_env(int pid, char * buffer)
{
struct mm_struct *mm = get_mm(pid);
return buffer;
}
-/*
- * These next two assume that the task's sigmask_lock is held by the caller.
- */
static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
sigset_t *catch)
{
cap_t(p->cap_effective));
}
-/*
- * This is somewhat safer than it was before. However...
- *
- * Embedded pointers in the task structure may reference data that
- * can be changed or that is no longer valid after the tasklist
- * lock is released, or that isn't even protected by the tasklist
- * lock. Eg. tsk->tty, tsk->sig, and tsk->p_pptr can change after
- * we make our own copy of the task structure. This doesn't matter
- * unless we are trying to use the pointed-to data as an address.
- * So there are still a few safety issues to be addressed here.
- */
+
static int get_status(int pid, char * buffer)
{
char * orig = buffer;
struct task_struct *tsk;
struct mm_struct *mm = NULL;
- /*
- * We lock the whole kernel here because p->files and p->mm are still
- * protected by the global kernel lock.
- */
- lock_kernel();
-
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
- if (tsk) {
+ if (tsk)
mm = tsk->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
-
- buffer = task_name(tsk, buffer);
- buffer = task_state(tsk, buffer);
-
- spin_lock_irq(&tsk->sigmask_lock);
- buffer = task_sig(tsk, buffer);
- spin_unlock_irq(&tsk->sigmask_lock);
-
- buffer = task_cap(tsk, buffer);
- }
- read_unlock(&tasklist_lock);
-
- unlock_kernel();
-
- /*
- * We can't hold the tasklist_lock and jiggle the mmap_sem --
- * that can result in a deadlock.
- */
- if (mm) {
+ if (mm)
+ atomic_inc(&mm->mm_users);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
+ if (!tsk)
+ return 0;
+ buffer = task_name(tsk, buffer);
+ buffer = task_state(tsk, buffer);
+ if (mm)
buffer = task_mem(mm, buffer);
+ buffer = task_sig(tsk, buffer);
+ buffer = task_cap(tsk, buffer);
+ if (mm)
mmput(mm);
- }
-
- /*
- * (buffer - orig) will be zero on an error exit.
- */
return buffer - orig;
}
static int get_stat(int pid, char * buffer)
{
struct task_struct *tsk;
- struct mm_struct *mm;
+ struct mm_struct *mm = NULL;
unsigned long vsize, eip, esp, wchan;
long priority, nice;
- pid_t ppid = 0;
+ int tty_pgrp;
sigset_t sigign, sigcatch;
char state;
- int res = 0;
- unsigned int tty_device;
- int tty_pgrp;
+ int res;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
- if (!tsk)
- goto out_unlock;
- /* avoid the task list to go away under us (security) */
- get_page(MAP_NR(tsk) + mem_map);
- ppid = tsk->p_pptr->pid;
- read_unlock(&tasklist_lock);
-
- /* we need the big kernel lock to avoid tsk->mm and tsk->tty
- to change under us */
- lock_kernel();
- mm = tsk->mm;
+ if (tsk)
+ mm = tsk->mm;
if (mm)
atomic_inc(&mm->mm_users);
- tty_device = tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0;
- tty_pgrp = tsk->tty ? tsk->tty->pgrp : -1;
- unlock_kernel();
-
- spin_lock_irq(&tsk->sigmask_lock);
- collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
- spin_unlock_irq(&tsk->sigmask_lock);
-
- eip = KSTK_EIP(tsk);
- esp = KSTK_ESP(tsk);
- wchan = get_wchan(tsk);
-
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
+ if (!tsk)
+ return 0;
state = *get_task_state(tsk);
vsize = eip = esp = 0;
- if (mm)
- {
+ if (mm) {
struct vm_area_struct *vma;
down(&mm->mmap_sem);
- for (vma = mm->mmap; vma; vma = vma->vm_next)
+ vma = mm->mmap;
+ while (vma) {
vsize += vma->vm_end - vma->vm_start;
+ vma = vma->vm_next;
+ }
+ eip = KSTK_EIP(tsk);
+ esp = KSTK_ESP(tsk);
up(&mm->mmap_sem);
}
+ wchan = get_wchan(tsk);
+
+ collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
+
+ if (tsk->tty)
+ tty_pgrp = tsk->tty->pgrp;
+ else
+ tty_pgrp = -1;
+
/* scale priority and nice values from timeslices to -20..20 */
/* to make it look like a "normal" Unix priority/nice value */
priority = tsk->counter;
pid,
tsk->comm,
state,
- ppid,
+ tsk->p_pptr->pid,
tsk->pgrp,
tsk->session,
- tty_device,
+ tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
tty_pgrp,
tsk->flags,
tsk->min_flt,
tsk->cnswap,
tsk->exit_signal,
tsk->processor);
-
if (mm)
mmput(mm);
- free_task_struct(tsk);
return res;
-
-out_unlock:
- read_unlock(&tasklist_lock);
- unlock_kernel();
- return 0;
}
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
size_t count, loff_t *ppos)
{
struct task_struct *p;
- struct mm_struct *mm = NULL;
struct vm_area_struct * map, * next;
char * destptr = buf, * buffer;
loff_t lineno;
ssize_t column, i;
+ int volatile_task;
long retval;
/*
goto out;
retval = -EINVAL;
- lock_kernel();
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
- if (p) {
- mm = p->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- }
- read_unlock(&tasklist_lock);
- unlock_kernel();
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p)
goto freepage_out;
- /* nothing to map */
- if (!mm || count == 0)
+ if (!p->mm || count == 0)
goto getlen_out;
+ /* Check whether the mmaps could change if we sleep */
+ volatile_task = (p != current || atomic_read(&p->mm->mm_users) > 1);
+
/* decode f_pos */
lineno = *ppos >> MAPS_LINE_SHIFT;
column = *ppos & (MAPS_LINE_LENGTH-1);
- down(&mm->mmap_sem);
- /* quickly go to line "lineno" */
- for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+ /* quickly go to line lineno */
+ for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
for ( ; map ; map = next ) {
/* done? */
if (count == 0)
break;
+
+ /* By writing to user space, we might have slept.
+ * Stop the loop, to avoid a race condition.
+ */
+ if (volatile_task)
+ break;
}
- up(&mm->mmap_sem);
/* encode f_pos */
*ppos = (lineno << MAPS_LINE_SHIFT) + column;
- mmput(mm);
getlen_out:
retval = destptr - buf;
#ifdef __SMP__
static int get_pidcpu(int pid, char * buffer)
{
- struct task_struct * tsk;
- int i, len = 0;
+ struct task_struct * tsk = current ;
+ int i, len;
- /*
- * Hold the tasklist_lock to guarantee that the task_struct
- * address will remain valid while we examine its contents.
- */
read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- if (tsk)
- get_page(MAP_NR(tsk) + mem_map);
- read_unlock(&tasklist_lock);
- if (tsk) {
- len = sprintf(buffer,
- "cpu %lu %lu\n",
- tsk->times.tms_utime,
- tsk->times.tms_stime);
+ if (pid != tsk->pid)
+ tsk = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
+
+ if (tsk == NULL)
+ return 0;
+
+ len = sprintf(buffer,
+ "cpu %lu %lu\n",
+ tsk->times.tms_utime,
+ tsk->times.tms_stime);
- for (i = 0 ; i < smp_num_cpus; i++)
- len += sprintf(buffer + len, "cpu%d %lu %lu\n",
- i,
- tsk->per_cpu_utime[cpu_logical_map(i)],
- tsk->per_cpu_stime[cpu_logical_map(i)]);
- free_task_struct(tsk);
- }
+ for (i = 0 ; i < smp_num_cpus; i++)
+ len += sprintf(buffer + len, "cpu%d %lu %lu\n",
+ i,
+ tsk->per_cpu_utime[cpu_logical_map(i)],
+ tsk->per_cpu_stime[cpu_logical_map(i)]);
+
return len;
}
#endif
int ok = 0;
read_lock(&tasklist_lock);
+
+ /*
+ * Grab the lock, find the task, save the uid and
+ * check it has an mm still (ie its not dead)
+ */
+
p = find_task_by_pid(pid);
if (p) {
euid=p->euid;
if(!cap_issubset(p->cap_permitted, current->cap_permitted))
ok=0;
}
+
read_unlock(&tasklist_lock);
+
if (!p)
return 1;
*
* A __PAGE_OFFSET of 0xC0000000 means that the kernel has
* a virtual address space of one gigabyte, which limits the
- * amount of physical memory you can use to about 950MB. If
- * you want to use more physical memory, change this define.
+ * amount of physical memory you can use to about 950MB.
*
- * For example, if you have 2GB worth of physical memory, you
- * could change this define to 0x80000000, which gives the
- * kernel 2GB of virtual memory (enough to most of your physical memory
- * as the kernel needs a bit extra for various io-memory mappings)
- *
- * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
- *
- * arch/i386/vmlinux.lds
- *
- * which has the same constant encoded..
+ * If you want more physical memory than this then see the CONFIG_BIGMEM
+ * option in the kernel configuration.
*/
-#include <asm/page_offset.h>
-
-#define __PAGE_OFFSET (PAGE_OFFSET_RAW)
+#define __PAGE_OFFSET (0xC0000000)
#ifndef __ASSEMBLY__
+++ /dev/null
-#include <linux/config.h>
-#ifdef CONFIG_1GB
-#define PAGE_OFFSET_RAW 0xC0000000
-#elif defined(CONFIG_2GB)
-#define PAGE_OFFSET_RAW 0x80000000
-#elif defined(CONFIG_3GB)
-#define PAGE_OFFSET_RAW 0x40000000
-#endif
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
- * Copyright (C) 1999 by Niibe Yutaka
+ * Copyright (C) 1999 by Kaz Kojima
*
* Defitions for the address spaces of the SH CPUs.
*/
#ifndef __ASM_SH_ADDRSPACE_H
#define __ASM_SH_ADDRSPACE_H
-/*
- * Memory segments (32bit kernel mode addresses)
- */
-#define KUSEG 0x00000000
-#define KSEG0 0x80000000
-#define KSEG1 0xa0000000
-#define KSEG2 0xc0000000
-#define KSEG3 0xe0000000
+/* Memory segments (32bit Priviledged mode addresses) */
+#define P0SEG 0x00000000
+#define P1SEG 0x80000000
+#define P2SEG 0xa0000000
+#define P3SEG 0xc0000000
+#define P4SEG 0xe0000000
-/*
- * Returns the kernel segment base of a given address
- */
-#define KSEGX(a) (((unsigned long)(a)) & 0xe0000000)
+#if defined(__sh3__)
+/* Should fill here */
+#elif defined(__SH4__)
+/* Detailed P4SEG */
+#define P4SEG_STORE_QUE (P4SEG)
+#define P4SEG_IC_ADDR 0xf0000000
+#define P4SEG_IC_DATA 0xf1000000
+#define P4SEG_ITLB_ADDR 0xf2000000
+#define P4SEG_ITLB_DATA 0xf3000000
+#define P4SEG_OC_ADDR 0xf4000000
+#define P4SEG_OC_DATA 0xf5000000
+#define P4SEG_TLB_ADDR 0xf6000000
+#define P4SEG_TLB_DATA 0xf7000000
+#define P4SEG_REG_BASE 0xff000000
+#endif
-/*
- * Returns the physical address of a KSEG0/KSEG1 address
- */
-#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
+/* Returns the privileged segment base of a given address */
+#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
+
+/* Returns the physical address of a PnSEG (n=1,2) address */
+#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
/*
- * Map an address to a certain kernel segment
+ * Map an address to a certain privileged segment
*/
-#define KSEG0ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG0))
-#define KSEG1ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG1))
-#define KSEG2ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG2))
-#define KSEG3ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG3))
+#define P1SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P1SEG))
+#define P2SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P2SEG))
+#define P3SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
+#define P4SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
#endif /* __ASM_SH_ADDRSPACE_H */
* on us. We need to use _exactly_ the address the user gave us,
* not some alias that contains the same information.
*/
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
/*
* To get proper branch prediction for the main line, we must branch
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*(long *)v += i;
restore_flags(flags);
}
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*(long *)v -= i;
restore_flags(flags);
}
{
unsigned long temp, flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
temp = *(long *)v;
temp += i;
*(long *)v = temp;
{
unsigned long temp, flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
temp = *(long *)v;
temp -= i;
*(long *)v = temp;
#define atomic_inc(v) atomic_add(1,(v))
#define atomic_dec(v) atomic_sub(1,(v))
-extern __inline__ void atomic_clear_mask(int mask, atomic_t *v)
+extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*(long *)v &= ~mask;
restore_flags(flags);
}
-extern __inline__ void atomic_set_mask(int mask, atomic_t *v)
+extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*(long *)v |= mask;
restore_flags(flags);
}
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*a |= mask;
restore_flags(flags);
}
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*a &= ~mask;
restore_flags(flags);
}
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*a ^= mask;
restore_flags(flags);
}
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- save_flags(flags);
- cli();
+ save_and_cli(flags);
retval = (mask & *a) != 0;
*a |= mask;
restore_flags(flags);
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- save_flags(flags);
- cli();
+ save_and_cli(flags);
retval = (mask & *a) != 0;
*a &= ~mask;
restore_flags(flags);
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- save_flags(flags);
- cli();
+ save_and_cli(flags);
retval = (mask & *a) != 0;
*a ^= mask;
restore_flags(flags);
__asm__("1:\n"
"shlr %1\n\t"
"bt/s 1b\n\t"
- "add #1, %0"
+ " add #1, %0"
: "=r" (result)
: "r" (word), "0" (~0L));
return result;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
- save_flags(flags); cli();
+ save_and_cli(flags);
retval = (mask & *ADDR) != 0;
*ADDR |= mask;
restore_flags(flags);
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
- save_flags(flags); cli();
+ save_and_cli(flags);
retval = (mask & *ADDR) != 0;
*ADDR &= ~mask;
restore_flags(flags);
static void __init check_bugs(void)
{
+ extern unsigned long loops_per_sec;
+
+ cpu_data->loops_per_sec = loops_per_sec;
+
+ switch (cpu_data->type) {
+ case CPU_SH7708:
+ printk("CPU: SH7708/SH7709\n");
+ break;
+ case CPU_SH7729:
+ printk("CPU: SH7709A/SH7729\n");
+ break;
+ case CPU_SH7750:
+ printk("CPU: SH7750\n");
+ break;
+ default:
+ printk("CPU: ??????\n");
+ break;
+ }
}
#endif /* __ASM_SH_BUGS_H */
* Copyright (C) 1999 Niibe Yutaka
*/
-#include <linux/config.h>
#include <asm/types.h>
static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
# define __SWAB_64_THRU_32__
#endif
-#ifdef CONFIG_LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN__
#include <linux/byteorder/little_endian.h>
#else
#include <linux/byteorder/big_endian.h>
#define __ASM_SH_CACHE_H
/* bytes per L1 cache line */
+#if defined(__sh3__)
#define L1_CACHE_BYTES 16
+#elif defined(__SH4__)
+#define L1_CACHE_BYTES 32
+#endif
#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
__section__(".data.cacheline_aligned")))
#endif
+extern void cache_flush_area(unsigned long start, unsigned long end);
+extern void cache_purge_area(unsigned long start, unsigned long end);
+extern void cache_wback_area(unsigned long start, unsigned long end);
+
#endif /* __ASM_SH_CACHE_H */
#ifndef __ASM_SH_CHECKSUM_H
#define __ASM_SH_CHECKSUM_H
-
-/*
- * This is a version of ip_compute_csum() optimized for IP headers,
- * which always checksum on 4 octet boundaries.
- */
-extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
-
/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
+ * 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.
+ *
+ * Copyright (C) 1999 by Kaz Kojima & Niibe Yutaka
*/
-extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
- unsigned long daddr,
- unsigned short len,
- unsigned short proto,
- unsigned int sum);
/*
* computes the checksum of a memory block at buff, length len,
*
* it's best to have buff aligned on a 32-bit boundary
*/
-extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
/*
* the same as csum_partial, but copies from src while it
- * checksums
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
*
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*/
-unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum);
+
+asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+ int *src_err_ptr, int *dst_err_ptr);
+
+/*
+ * Note: when you get a NULL pointer exception here this means someone
+ * passed in an incorrect kernel address to one of these functions.
+ *
+ * If you use these functions directly please don't forget the
+ * verify_area().
+ */
+extern __inline__
+unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+ int len, int sum)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+}
+
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+}
+
+#if 0
+
+/* Not used at the moment. It is difficult to imagine for what purpose
+ it can be used :-) Please, do not forget to verify_area before it --ANK
+ */
+
+/*
+ * This combination is currently not used, but possible:
+ */
+
+extern __inline__
+unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, NULL, err_ptr);
+}
+#endif
/*
- * the same as csum_partial, but copies from user space (but on the alpha
- * we have just one address space, so this is identical to the above)
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
*
- * this is obsolete and will go away.
+ * these functions should go away after some time.
*/
+
#define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
/*
- * this is a new version of the above that records errors it finds in *errp,
- * but continues and zeros the rest of the buffer.
+ * Fold a partial checksum
*/
-unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
+
+static __inline__ unsigned int csum_fold(unsigned int sum)
+{
+ unsigned int __dummy;
+ __asm__("clrt\n\t"
+ "mov %0,%1\n\t"
+ "shll16 %0\n\t"
+ "addc %0,%1\n\t"
+ "movt %0\n\t"
+ "shlr16 %1\n\t"
+ "add %1,%0"
+ : "=r" (sum), "=&r" (__dummy)
+ : "0" (sum));
+ return ~sum;
+}
/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted
+ * for linux by * Arnt Gulbrandsen.
*/
+static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+ unsigned int sum, __dummy;
+
+ __asm__ __volatile__(
+ "mov.l @%1+,%0\n\t"
+ "add #-4,%2\n\t"
+ "clrt\n\t"
+ "mov.l @%1+,%3\n\t"
+ "addc %3,%0\n\t"
+ "mov.l @%1+,%3\n\t"
+ "addc %3,%0\n\t"
+ "mov.l @%1+,%3\n\t"
+ "addc %3,%0\n"
+ "1:\t"
+ "mov.l @%1+,%3\n\t"
+ "addc %3,%0\n\t"
+ "movt %3\n\t"
+ "dt %2\n\t"
+ "bf/s 1b\n\t"
+ " cmp/eq #1,%3\n\t"
+ "mov #0,%3\n\t"
+ "addc %3,%0\n\t"
+ /* Since the input registers which are loaded with iph and ihl
+ are modified, we must also specify them as outputs, or gcc
+ will assume they contain their original values. */
+ : "=r" (sum), "=r" (iph), "=r" (ihl), "=&z" (__dummy)
+ : "1" (iph), "2" (ihl));
+
+ return csum_fold(sum);
+}
-extern unsigned short ip_compute_csum(unsigned char * buff, int len);
+static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+#ifdef __LITTLE_ENDIAN__
+ unsigned long len_proto = (ntohs(len)<<16)+proto*256;
+#else
+ unsigned long len_proto = (proto<<16)+len;
+#endif
+ __asm__("clrt\n\t"
+ "addc %0,%1\n\t"
+ "addc %2,%1\n\t"
+ "addc %3,%1\n\t"
+ "movt %0\n\t"
+ "add %1,%0"
+ : "=r" (sum), "=r" (len_proto)
+ : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
+ return sum;
+}
/*
- * Fold a partial checksum without adding pseudo headers
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
*/
+static __inline__ unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
-static inline unsigned short csum_fold(unsigned int sum)
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
{
- sum = (sum & 0xffff) + (sum >> 16);
- sum = (sum & 0xffff) + (sum >> 16);
- return ~sum;
+ return csum_fold (csum_partial(buff, len, 0));
}
#define _HAVE_ARCH_IPV6_CSUM
-/*
-extern unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
- struct in6_addr *daddr,
- __u16 len,
- unsigned short proto,
- unsigned int sum);
-*/
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ unsigned int __dummy;
+ __asm__("clrt\n\t"
+ "mov.l @(0,%2),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(4,%2),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(8,%2),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(12,%2),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(0,%3),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(4,%3),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(8,%3),%1\n\t"
+ "addc %1,%0\n\t"
+ "mov.l @(12,%3),%1\n\t"
+ "addc %1,%0\n\t"
+ "addc %4,%0\n\t"
+ "addc %5,%0\n\t"
+ "movt %1\n\t"
+ "add %1,%0\n"
+ : "=r" (sum), "=&r" (__dummy)
+ : "r" (saddr), "r" (daddr),
+ "r" (htonl((__u32) (len))), "r" (htonl(proto)), "0" (sum));
+
+ return csum_fold(sum);
+}
+
+/*
+ * Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ if (access_ok(VERIFY_WRITE, dst, len))
+ return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return -1; /* invalid checksum */
+}
#endif /* __ASM_SH_CHECKSUM_H */
#define __ASM_SH_DELAY_H
/*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999 Kaz Kojima
*/
extern __inline__ void __delay(unsigned long loops)
{
- unsigned long __dummy;
__asm__ __volatile__(
- "1:\t"
- "dt %0\n\t"
- "bf 1b"
- :"=r" (__dummy)
- :"0" (loops));
+ "tst %0,%0\n\t"
+ "1:\t"
+ "bf/s 1b\n\t"
+ " dt %0"
+ : "=r" (loops)
+ : "0" (loops));
}
extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
{
usecs *= 0x000010c6; /* 2**32 / 1000000 */
- __asm__("mul.l %0,%2\n\t"
- "sts macl,%0"
- : "=&r" (usecs)
+ __asm__("dmulu.l %0,%2\n\t"
+ "sts mach,%0"
+ : "=r" (usecs)
: "0" (usecs), "r" (lps)
: "macl", "mach");
__delay(usecs);
#define udelay(usecs) __udelay((usecs),__udelay_val)
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
-{
- return (a*b)/c;
-}
-
#endif /* __ASM_SH_DELAY_H */
* ELF register definitions..
*/
-#include <linux/config.h>
#include <asm/ptrace.h>
#include <asm/user.h>
#include <asm/byteorder.h>
#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-#ifdef CONFIG_CPU_SH4
+/* Though SH-3 has no floating point regs.. */
+#define ELF_NFPREG 34
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-#else /* SH 3 has no floating point regs */
-typedef struct { void *null; } elf_fpregset_t;
-#endif
/*
* This is used to ensure we don't load something for the wrong architecture.
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
-#ifdef __LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN__
#define ELF_DATA ELFDATA2LSB
#else
#define ELF_DATA ELFDATA2MSB
#define ELF_PLATFORM (NULL)
+#define ELF_PLAT_INIT(_r) \
+ do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
+ _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \
+ _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \
+ _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; } while (0)
+
#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) \
current->personality = PER_LINUX_32BIT
#define hardirq_enter(cpu) (local_irq_count[cpu]++)
#define hardirq_exit(cpu) (local_irq_count[cpu]--)
-#define synchronize_irq() do { } while (0)
+#define synchronize_irq() barrier()
#else
--- /dev/null
+/*
+ * linux/include/asm-sh/hdreg.h
+ *
+ * Copyright (C) 1994-1996 Linus Torvalds & authors
+ */
+
+#ifndef __ASM_SH_HDREG_H
+#define __ASM_SH_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif /* __ASM_SH_HDREG_H */
--- /dev/null
+/*
+ * linux/include/asm-sh/ide.h
+ *
+ * Copyright (C) 1994-1996 Linus Torvalds & authors
+ */
+
+/*
+ * This file contains the i386 architecture specific IDE code.
+ * In future, SuperH code.
+ */
+
+#ifndef __ASM_SH_IDE_H
+#define __ASM_SH_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+#define MAX_HWIFS 10
+#endif
+
+#define ide__sti() __sti()
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+ switch (base) {
+ case 0x1f0: return 14;
+ case 0x170: return 15;
+ case 0x1e8: return 11;
+ case 0x168: return 10;
+ case 0x1e0: return 8;
+ case 0x160: return 12;
+ default:
+ return 0;
+ }
+}
+
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+ switch (index) {
+ case 0: return 0x1f0;
+ case 1: return 0x170;
+ case 2: return 0x1e8;
+ case 3: return 0x168;
+ case 4: return 0x1e0;
+ case 5: return 0x160;
+ default:
+ return 0;
+ }
+}
+
+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;
+
+ 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)
+{
+#ifndef CONFIG_BLK_DEV_IDEPCI
+ 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 /* CONFIG_BLK_DEV_IDEPCI */
+}
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned head : 4; /* always zeros here */
+ unsigned unit : 1; /* drive select number, 0 or 1 */
+ unsigned bit5 : 1; /* always 1 */
+ unsigned lba : 1; /* using LBA instead of CHS */
+ unsigned bit7 : 1; /* always 1 */
+ } b;
+ } select_t;
+
+#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
+ */
+#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__ */
+
+#endif /* __ASM_SH_IDE_H */
#ifndef __ASM_SH_IO_H
#define __ASM_SH_IO_H
-/* XXXXXXXXXXXXXXXXX */
+
+/*
+ * Convention:
+ * read{b,w,l}/write{b,w,l} are for PCI,
+ * while in{b,w,l}/out{b,w,l} are for ISA
+ * These may (will) be platform specific function.
+ *
+ * In addition, we have
+ * ctrl_in{b,w,l}/ctrl_out{b,w,l} for SuperH specific I/O.
+ * which are processor specific.
+ */
+
+#include <asm/cache.h>
#define virt_to_bus virt_to_phys
#define bus_to_virt phys_to_virt
return *(volatile unsigned long*)addr;
}
-extern __inline__ void writeb(unsigned short b, unsigned long addr)
+extern __inline__ void writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
return writel(b,addr);
}
+extern __inline__ unsigned long ctrl_inb(unsigned long addr)
+{
+ return *(volatile unsigned char*)addr;
+}
+
+extern __inline__ unsigned long ctrl_inw(unsigned long addr)
+{
+ return *(volatile unsigned short*)addr;
+}
+
+extern __inline__ unsigned long ctrl_inl(unsigned long addr)
+{
+ return *(volatile unsigned long*)addr;
+}
+
+extern __inline__ void ctrl_outb(unsigned char b, unsigned long addr)
+{
+ *(volatile unsigned char*)addr = b;
+}
+
+extern __inline__ void ctrl_outw(unsigned short b, unsigned long addr)
+{
+ *(volatile unsigned short*)addr = b;
+}
+
+extern __inline__ void ctrl_outl(unsigned int b, unsigned long addr)
+{
+ *(volatile unsigned long*)addr = b;
+}
+
#define inb_p inb
#define outb_p outb
extern __inline__ void * phys_to_virt(unsigned long address)
{
- return (void *)KSEG0ADDR(address);
+ return (void *)P1SEGADDR(address);
}
extern void * ioremap(unsigned long phys_addr, unsigned long size);
*/
extern __inline__ void * ioremap(unsigned long offset, unsigned long size)
{
- return (void *) KSEG1ADDR(offset);
+ return (void *) P2SEGADDR(offset);
}
/*
*/
extern __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size)
{
- return (void *) KSEG1ADDR(offset);
+ return (void *) P2SEGADDR(offset);
}
extern __inline__ void iounmap(void *addr)
return retval;
}
-/* Nothing to do */
+/*
+ * The caches on some architectures aren't dma-coherent and have need to
+ * handle this in software. There are three types of operations that
+ * can be applied to dma buffers.
+ *
+ * - dma_cache_wback_inv(start, size) makes caches and RAM coherent by
+ * writing the content of the caches back to memory, if necessary.
+ * The function also invalidates the affected part of the caches as
+ * necessary before DMA transfers from outside to memory.
+ * - dma_cache_inv(start, size) invalidates the affected parts of the
+ * caches. Dirty lines of the caches may be written back or simply
+ * be discarded. This operation is necessary before dma operations
+ * to the memory.
+ * - dma_cache_wback(start, size) writes back any dirty lines but does
+ * not invalidate the cache. This can be used before DMA reads from
+ * memory,
+ */
-#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)
+#define dma_cache_wback_inv(_start,_size) \
+ cache_flush_area((unsigned long)(_start),((unsigned long)(_start)+(_size)))
+#define dma_cache_inv(_start,_size) \
+ cache_purge_area((unsigned long)(_start),((unsigned long)(_start)+(_size)))
+#define dma_cache_wback(_start,_size) \
+ cache_wback_area((unsigned long)(_start),((unsigned long)(_start)+(_size)))
#endif /* __KERNEL__ */
#endif /* __ASM_SH_IO_H */
-/* $Id: ioctl.h,v 1.5 1993/07/19 21:53:50 root Exp root $
+/* $Id: ioctl.h,v 1.1 1999/09/18 17:29:53 gniibe Exp $
*
* linux/ioctl.h for Linux by H.H. Bergman.
*/
#define TIOCSTI _IOW('T', 18, char) /* 0x5412 */
#define TIOCMGET _IOR('T', 21, unsigned int) /* 0x5415 */
-#define TIOCMBIS _IOW('T', 22, unsigne int) /* 0x5416 */
-#define TIOCMBIC _IOW('T', 23, unsigne int) /* 0x5417 */
-#define TIOCMSET _IOW('T', 24, unsigne int) /* 0x5418 */
+#define TIOCMBIS _IOW('T', 22, unsigned int) /* 0x5416 */
+#define TIOCMBIC _IOW('T', 23, unsigned int) /* 0x5417 */
+#define TIOCMSET _IOW('T', 24, unsigned int) /* 0x5418 */
# define TIOCM_LE 0x001
# define TIOCM_DTR 0x002
# define TIOCM_RTS 0x004
#define TIMER_PRIORITY 1
/*
- * 40 = 24+16
+ * 48 = 32+16
*
- * 24 for on chip support modules.
+ * 32 for on chip support modules.
* 16 for external interrupts.
*
*/
-#define NR_IRQS 40
+#define NR_IRQS 48
extern void disable_irq(unsigned int);
extern void disable_irq_nosync(unsigned int);
extern __inline__ void
get_new_mmu_context(struct mm_struct *mm)
{
+ extern void flush_tlb_all(void);
+
unsigned long mc = ++mmu_context_cache;
if (!(mc & MMU_CONTEXT_ASID_MASK)) {
mm->context = mc;
}
-/*P
+/*
* Get MMU context if needed.
*/
extern __inline__ void
}
}
-/*P
+/*
* Initialize the context related info for a new mm_struct
* instance.
*/
mm->context = NO_CONTEXT;
}
-/*P
+/*
* Destroy context related info for an mm_struct that is about
* to be put to rest.
*/
/* Other MMU related constants. */
+#if defined(__sh3__)
#define MMU_PTEH 0xFFFFFFF0 /* Page table entry register HIGH */
#define MMU_PTEL 0xFFFFFFF4 /* Page table entry register LOW */
+#define MMU_TTB 0xFFFFFFF8 /* Translation table base register */
+#define MMU_TEA 0xFFFFFFFC /* TLB Exception Address */
+
#define MMUCR 0xFFFFFFE0 /* MMU Control Register */
#define MMU_TLB_ADDRESS_ARRAY 0xF2000000
#define MMU_PAGE_ASSOC_BIT 0x80
#define MMU_NTLB_ENTRIES 128 /* for 7708 */
-
#define MMU_CONTROL_INIT 0x007 /* SV=0, TF=1, IX=1, AT=1 */
-#include <asm/uaccess.h> /* to get the definition of __m */
+#elif defined(__SH4__)
+#define MMU_PTEH 0xFF000000 /* Page table entry register HIGH */
+#define MMU_PTEL 0xFF000004 /* Page table entry register LOW */
+#define MMU_TTB 0xFF000008 /* Translation table base register */
+#define MMU_TEA 0xFF00000C /* TLB Exception Address */
+
+#define MMUCR 0xFF000010 /* MMU Control Register */
+
+#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000
+#define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
+#define MMU_PAGE_ASSOC_BIT 0x80
+
+#define MMU_NTLB_ENTRIES 64 /* for 7750 */
+#define MMU_CONTROL_INIT 0x205 /* SQMD=1, SV=0, TI=1, AT=1 */
+#endif
extern __inline__ void set_asid (unsigned long asid)
{
return asid;
}
-/*P
+/*
* After we have set current->mm to a new value, this activates
* the context for the new mm so we see the new mappings.
*/
/* MMU_TTB can be used for optimizing the fault handling.
(Currently not used) */
-#define MMU_TTB 0xFFFFFFF8 /* Translation table base register */
extern __inline__ void switch_mm(struct mm_struct *prev,
struct mm_struct *next,
struct task_struct *tsk, unsigned int cpu)
-/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
+/* $Id: namei.h,v 1.1 1999/09/18 17:30:11 gniibe Exp $
* linux/include/asm-sh/namei.h
*
* Included from linux/fs/namei.c
* Copyright (C) 1999 Niibe Yutaka
*/
-/* XXX
- [ P0 (virtual) ] 0x00000000 <------ User space
- [ P1 (fixed) write-through] 0x80000000 <------ Kernel space
- [ P2 (fixed) non-cachable] 0xA0000000 <------ Physical access
- [ P3 (virtual) write-back] 0xC0000000 <------ not used
- [ P4 control ] 0xE0000000
+/*
+ [ P0/U0 (virtual) ] 0x00000000 <------ User space
+ [ P1 (fixed) cached ] 0x80000000 <------ Kernel space
+ [ P2 (fixed) non-cachable] 0xA0000000 <------ Physical access
+ [ P3 (virtual) cached] 0xC0000000 <------ not used
+ [ P4 control ] 0xE0000000
*/
#include <linux/config.h>
/* Copyright (C) 1999 Niibe Yutaka */
-#include <linux/config.h>
-
/*
* This file contains the functions and defines necessary to modify and use
* the SuperH page table tree.
*/
#ifndef __ASSEMBLY__
#include <asm/processor.h>
+#include <asm/addrspace.h>
#include <linux/threads.h>
extern pgd_t swapper_pg_dir[1024];
-#ifdef CONFIG_CPU_SH3
+#if defined(__sh3__)
/* Cache flushing:
*
* - flush_cache_all() flushes entire cache
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
-#elif CONFIG_CPU_SH4
+#elif defined(__SH4__)
/*
* Caches are broken on SH-4, so we need them.
- * You do bad job!
*/
-flush_cache_all()
-flush_cache_mm(mm)
-flush_cache_range(mm, start, end)
-flush_cache_page(vma, vmaddr)
-flush_page_to_ram(page)
-flush_icache_range(start, end)
+extern void flush_cache_all(void);
+extern void flush_cache_mm(struct mm_struct *mm);
+extern void flush_cache_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_page_to_ram(unsigned long page);
+extern void flush_icache_range(unsigned long start, unsigned long end);
#endif
/* TLB flushing:
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#ifndef __ASSEMBLY__
-#define VMALLOC_START 0xc0000000
+#define VMALLOC_START P3SEG
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END 0xe0000000
+#define VMALLOC_END P4SEG
#define _PAGE_READ 0x001 /* software: read access alowed */
#define _PAGE_ACCESSED 0x002 /* software: page referenced */
/* 0x080 */
#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */
+#if defined(__sh3__)
/* Mask which drop software flags */
-#define _PAGE_FLAGS_HARDWARE_MASK 0xfffff164
+#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff164
/* Flags defalult: SZ=1 (4k-byte), C=1 (cachable), SH=0 (not shared) */
#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x00000018
-
+#elif defined(__SH4__)
+/* Mask which drops software flags */
+#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff164
+/* Flags defalult: SZ=01 (4k-byte), C=1 (cachable), SH=0 (not shared), WT=0 */
+#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x00000018
+#endif
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
*/
+enum cpu_type {
+ CPU_SH7708, /* Represents 7708, 7708S, 7708R, 7709 */
+ CPU_SH7729, /* Represents 7709A, 7729 */
+ CPU_SH7750,
+ CPU_SH_NONE
+};
struct sh_cpuinfo {
+ enum cpu_type type;
unsigned long loops_per_sec;
+
+ char hard_math;
+
+ /* Not yet used */
unsigned long *pgd_quick;
unsigned long *pte_quick;
unsigned long pgtable_cache_sz;
extern struct sh_cpuinfo boot_cpu_data;
-#define cpu_data &boot_cpu_data
+#define cpu_data (&boot_cpu_data)
#define current_cpu_data boot_cpu_data
/*
*/
#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define NUM_FPU_REGS 16
+
+struct sh_fpu_hard_struct {
+ unsigned long fp_regs[NUM_FPU_REGS];
+ unsigned long xf_regs[NUM_FPU_REGS];
+ unsigned long fpscr;
+ unsigned long fpul;
+
+ long status; /* software status information */
+};
+
+/* Dummy fpu emulator */
+struct sh_fpu_soft_struct {
+ unsigned long fp_regs[NUM_FPU_REGS];
+ unsigned long xf_regs[NUM_FPU_REGS];
+ unsigned long fpscr;
+ unsigned long fpul;
+
+ unsigned char lookahead;
+ unsigned long entry_pc;
+};
+
+union sh_fpu_union {
+ struct sh_fpu_hard_struct hard;
+ struct sh_fpu_soft_struct soft;
+};
+
struct thread_struct {
unsigned long sp;
unsigned long pc;
unsigned long trap_no, error_code;
unsigned long address;
/* Hardware debugging registers may come here */
+
+ /* floating point info */
+ union sh_fpu_union fpu;
};
#define INIT_MMAP \
sizeof(init_stack) + (long) &init_stack, /* sp */ \
0, /* pc */ \
0, 0, \
+ 0, \
+ {{{0,}},} \
}
/*
regs->pr = 0; \
regs->sr = 0; /* User mode. */ \
regs->pc = new_pc; \
- regs->u_regs[UREG_SP] = new_sp
+ regs->sp = new_sp
/* Forward declaration, a strange C thing */
struct task_struct;
#define release_segments(mm) do { } while(0)
#define forget_segments() do { } while (0)
+/*
+ * FPU lazy state save handling..
+ */
+#define SR_FD 0x00008000
+
+extern __inline__ void release_fpu(void)
+{
+ unsigned long __dummy;
+
+ /* Set FD flag in SR */
+ __asm__ __volatile__ ("stc sr,%0\n\t"
+ "or %1,%0\n\t"
+ "ldc %0,sr"
+ : "=&r" (__dummy)
+ : "r" (SR_FD));
+}
+
+extern __inline__ void grab_fpu(void)
+{
+ unsigned long __dummy;
+
+ /* Clear out FD flag in SR */
+ __asm__ __volatile__ ("stc sr,%0\n\t"
+ "and %1,%0\n\t"
+ "ldc %0,sr"
+ : "=&r" (__dummy)
+ : "r" (~SR_FD));
+}
+
+extern void save_fpu(struct task_struct *__tsk);
+
+#define unlazy_fpu(tsk) do { \
+ if (tsk->flags & PF_USEDFPU) \
+ save_fpu(tsk); \
+} while (0)
+
+#define clear_fpu(tsk) do { \
+ if (tsk->flags & PF_USEDFPU) { \
+ tsk->flags &= ~PF_USEDFPU; \
+ release_fpu(); \
+ } \
+} while (0)
+
/*
* Return saved PC of a blocked thread.
*/
#define __ASM_SH_PTRACE_H
/*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999 Niibe Yutaka
*
*/
*/
struct pt_regs {
long syscall_nr;
- unsigned long u_regs[16];
+ unsigned long sr;
+ unsigned long sp;
+ unsigned long regs[15];
unsigned long gbr;
unsigned long mach;
unsigned long macl;
unsigned long pr;
- unsigned long sr;
unsigned long pc;
};
extern void show_regs(struct pt_regs *);
#endif
-#define UREG_SP 15
#endif /* __ASM_SH_PTRACE_H */
unsigned long oldmask;
/* CPU registers */
- unsigned long u_regs[16];
- unsigned long gbr;
- unsigned long mach;
- unsigned long macl;
- unsigned long pr;
- unsigned long sr;
- unsigned long pc;
+ unsigned long sc_regs[15];
+ unsigned long sc_gbr;
+ unsigned long sc_mach;
+ unsigned long sc_macl;
+ unsigned long sc_pr;
+ unsigned long sc_sp;
+ unsigned long sc_sr;
+ unsigned long sc_pc;
};
#endif /* __ASM_SH_SIGCONTEXT_H */
/* Avoid too many header ordering problems. */
struct siginfo;
-#ifdef __KERNEL__
-/* Most things should be clean enough to redefine this at will, if care
- is taken to make libc match. */
-
#define _NSIG 64
#define _NSIG_BPW 32
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-#else
-/* Here we must cater to libcs that poke about in kernel headers. */
-
-#define NSIG 32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
+++ /dev/null
-#ifndef __ASM_SH_SMPLOCK_H
-#define __ASM_SH_SMPLOCK_H
-
-#ifndef __SMP__
-
-#define lock_kernel() do { } while(0)
-#define unlock_kernel() do { } while(0)
-#define release_kernel_lock(task, cpu, depth) ((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
-
-#else
-
-#error "We do not support SMP on SH yet"
-
-#endif /* __SMP__ */
-
-#endif /* __ASM_SH_SMPLOCK_H */
--- /dev/null
+#ifndef __ASM_SH_SMPLOCK_H
+#define __ASM_SH_SMPLOCK_H
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __SMP__
+
+#define lock_kernel() do { } while(0)
+#define unlock_kernel() do { } while(0)
+#define release_kernel_lock(task, cpu, depth) ((depth) = 1)
+#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
+
+#else
+
+#error "We do not support SMP on SH yet"
+/*
+ * Default SMP lock implementation
+ */
+
+#include <linux/interrupt.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t kernel_flag;
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+ if (!++current->lock_depth)
+ spin_lock(&kernel_flag);
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+ if (--current->lock_depth < 0)
+ spin_unlock(&kernel_flag);
+}
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu) \
+do { \
+ if (task->lock_depth >= 0) \
+ spin_unlock(&kernel_flag); \
+ release_irqlock(cpu); \
+ __sti(); \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task) \
+do { \
+ if (task->lock_depth >= 0) \
+ spin_lock(&kernel_flag); \
+} while (0)
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_SH_SMPLOCK_H */
#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
#define SO_SECURITY_ENCRYPTION_NETWORK 24
-/* Nasty libc5 fixup - bletch */
-#if defined(__KERNEL__)
-/* Socket types. */
-#define SOCK_STREAM 1 /* stream (connection) socket */
-#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
-#define SOCK_RAW 3 /* raw socket */
-#define SOCK_RDM 4 /* reliably-delivered message */
-#define SOCK_SEQPACKET 5 /* sequential packet socket */
-#define SOCK_PACKET 10 /* linux specific way of */
- /* getting packets at the dev */
- /* level. For writing rarp and */
- /* other similar things on the */
- /* user level. */
-#endif
+#define SO_BINDTODEVICE 25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER 26
+#define SO_DETACH_FILTER 27
#endif /* __ASM_SH_SOCKET_H */
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
#define get_active_bhs() (bh_mask & bh_active)
-/* XXX */
-#define clear_active_bhs(x) atomic_clear_mask((x),&bh_active)
+#define clear_active_bhs(x) atomic_clear_mask((x),(atomic_t *)&bh_active)
extern inline void init_bh(int nr, void (*routine)(void))
{
register unsigned long *__ts6 __asm__ ("r6") = &next->thread.sp; \
register unsigned long __ts7 __asm__ ("r7") = next->thread.pc; \
__asm__ __volatile__ (".balign 4\n\t" \
+ "stc.l gbr,@-r15\n\t" \
"sts.l pr,@-r15\n\t" \
"mov.l r8,@-r15\n\t" \
"mov.l r9,@-r15\n\t" \
"mov.l %0,@r2 ! save PC\n\t" \
"mov.l 2f,%0\n\t" \
"jmp @%0 ! call __switch_to\n\t" \
- " lds r7,pr ! with return to new PC\n" \
- "2:\n" \
- ".long " "_" "__switch_to\n\t" \
+ " lds r7,pr ! with return to new PC\n\t" \
".balign 4\n" \
- "1:\n" \
+ "2:\n\t" \
+ ".long " "_" "__switch_to\n" \
+ "1:\n\t" \
"mov.l @r15+,%0 ! pop R0 from new stack\n\t" \
"mov.l @r15+,r14\n\t" \
"mov.l @r15+,r13\n\t" \
"mov.l @r15+,r9\n\t" \
"mov.l @r15+,r8\n\t" \
"lds.l @r15+,pr\n\t" \
+ "ldc.l @r15+,gbr\n\t" \
:"=&z" (__last) \
:"0" (prev), \
"r" (__ts1), "r" (__ts2), \
#define mb() __asm__ __volatile__ ("": : :"memory")
#define rmb() mb()
#define wmb() __asm__ __volatile__ ("": : :"memory")
+#define set_rmb(var, value) do { xchg(&var, value); } while (0)
+#define set_mb(var, value) set_rmb(var, value)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
/* Interrupt Control */
extern __inline__ void __sti(void)
return retval;
}
-static __inline__ unsigned long __xchg(unsigned long x, void * ptr, int size)
+static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
switch (size) {
case 4:
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate (not used) */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
#define N_AX25 5
#define N_X25 6 /* X.25 async */
#define N_6PACK 7
-#define N_MASC 8 /* Reserved fo Mobitex module <kaz@cafe.net> */
+#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964 9 /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC 13 /* synchronous HDLC */
#ifdef __KERNEL__
*/
#ifdef __KERNEL__
-typedef signed char s8;
+typedef __signed__ char s8;
typedef unsigned char u8;
-typedef signed short s16;
+typedef __signed__ short s16;
typedef unsigned short u16;
-typedef signed int s32;
+typedef __signed__ int s32;
typedef unsigned int u32;
-typedef signed long long s64;
+typedef __signed__ long long s64;
typedef unsigned long long u64;
#define BITS_PER_LONG 32
-/*
+/* $Id: uaccess.h,v 1.3 1999/10/12 14:46:20 gniibe Exp $
+ *
* User space memory access functions
*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999 Niibe Yutaka
*
* Based on:
* MIPS implementation version 1.15 by
unsigned long flag,sum; \
__asm__("clrt; addc %3,%1; movt %0; cmp/hi %4,%1; rotcl %0" \
:"=&r" (flag), "=r" (sum) \
- :"1" (addr), "r" (size), "r" (current->addr_limit.seg)); \
+ :"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)); \
flag; })
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
"mov.l 5f,%1\n\t"
"jmp @%1\n\t"
" mov %7,%0\n\t"
- ".align 4\n"
+ ".balign 4\n"
"5: .long 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
- " .align 4\n"
+ " .balign 4\n"
" .long 9b,3b\n"
" .long 1b,2b\n"
".previous"
"mov.l 4f,%0\n\t"
"jmp @%0\n\t"
" mov %7,%0\n"
- ".align 4\n"
+ ".balign 4\n"
"4: .long 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
- " .align 4\n"
+ " .balign 4\n"
" .long 1b,3b\n"
".previous"
: "=&r" (res), "=&r" (__a), "=&r" (__s)
"mov.l 4f,%1\n\t"
"jmp @%1\n\t"
" mov %8,%0\n\t"
- ".align 4\n"
+ ".balign 4\n"
"4: .long 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
- " .align 4\n"
+ " .balign 4\n"
" .long 9b,3b\n"
" .long 1b,2b\n"
".previous"
__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
} __sfu_res; })
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
/*
* Return the size of a string (including the ending 0!)
*/
-extern __inline__ long __strlen_user(const char *__s)
+extern __inline__ long __strnlen_user(const char *__s, long __n)
{
unsigned long res;
unsigned long __dummy;
__asm__ __volatile__(
"mov #-1,%1\n"
- "9:\n"
+ "9:\n\t"
+ "cmp/eq %4,%0\n\t"
+ "bt 5f\n\t"
"cmp/eq #0,%1\n\t"
"bf/s 9b\n\t"
"1:\t"
" mov.b @%0+,%1\n\t"
+ "5:\t"
"sub %3,%0\n"
"2:\n"
".section .fixup,\"ax\"\n"
"3:\n\t"
"mov.l 4f,%1\n\t"
"jmp @%1\n\t"
- " mov %4,%0\n"
- ".align 4\n"
+ " mov %5,%0\n"
+ ".balign 4\n"
"4: .long 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
- " .align 4\n"
+ " .balign 4\n"
" .long 1b,3b\n"
".previous"
: "=&r" (res), "=&z" (__dummy)
- : "0" (__s), "r" (__s), "i" (-EFAULT));
+ : "0" (__s), "r" (__s), "r" (__s+__n), "i" (-EFAULT));
return res;
}
-extern __inline__ long strlen_user(const char *s)
+extern __inline__ long strnlen_user(const char *s, long n)
{
- if(!access_ok(VERIFY_READ, s, 0))
+ if(!access_ok(VERIFY_READ, s, n))
return 0;
else
- return __strlen_user(s);
+ return __strnlen_user(s, n);
}
struct exception_table_entry
register long __sc0 __asm__ ("r0") = __NR_##name; \
__asm__ __volatile__ ("trapa #0" \
: "=z" (__sc0) \
- : "0" (__sc0)); \
+ : "0" (__sc0) \
+ : "memory" ); \
__syscall_return(type,__sc0); \
}
register long __sc4 __asm__ ("r4") = (long) arg1; \
__asm__ __volatile__ ("trapa #0" \
: "=z" (__sc0) \
- : "0" (__sc0), "r" (__sc4)); \
+ : "0" (__sc0), "r" (__sc4) \
+ : "memory"); \
__syscall_return(type,__sc0); \
}
register long __sc5 __asm__ ("r5") = (long) arg2; \
__asm__ __volatile__ ("trapa #0" \
: "=z" (__sc0) \
- : "0" (__sc0), "r" (__sc4), "r" (__sc5)); \
+ : "0" (__sc0), "r" (__sc4), "r" (__sc5) \
+ : "memory"); \
__syscall_return(type,__sc0); \
}
register long __sc6 __asm__ ("r6") = (long) arg3; \
__asm__ __volatile__ ("trapa #0" \
: "=z" (__sc0) \
- : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)); \
+ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \
+ : "memory"); \
__syscall_return(type,__sc0); \
}
__asm__ __volatile__ ("trapa #0" \
: "=z" (__sc0) \
: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), \
- "r" (__sc7)); \
+ "r" (__sc7) \
+ : "memory" ); \
__syscall_return(type,__sc0); \
}
/* per-device flags */
__u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */
__u8 reserved : 6; /* not used yet */
+ __u32 packet_size; /* write out this number of packets */
+ __u32 nwa; /* next writeable address */
};
struct cdrom_device_ops {
__u8 uru : 1;
__u8 dbc_v : 1;
__u8 did_v : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
#endif
__u8 disc_type;
__u8 n_sessions_msb;
__u8 nwa_v : 1;
__u8 lra_v : 1;
__u8 reserved3 : 6;
-#else
-#error "Please fix <asm/byteorder.h>"
#endif
__u32 track_start;
__u32 next_writable;
__u8 reserved1 : 4;
__u8 door_open : 1;
__u8 mech_state : 3;
-#else
-#error "Please fix <asm/byteorder.h>"
#endif
__u8 curlba[3];
__u8 nslots;
__u8 short slot_tablelen;
};
-
struct cdrom_slot {
#if defined(__BIG_ENDIAN_BITFIELD)
__u8 disc_present : 1;
__u8 change : 1;
__u8 reserved1 : 6;
__u8 disc_present : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
#endif
__u8 reserved2[3];
};
mechtype_cartridge_changer = 5
} mechtype_t;
+struct mode_page_header {
+ __u16 mode_data_length;
+ __u8 medium_type;
+ __u8 reserved1;
+ __u8 reserved2;
+ __u8 reserved3;
+ __u16 desc_length;
+};
+
+typedef struct {
+ struct mode_page_header header;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ps : 1;
+ __u8 reserved1 : 1;
+ __u8 page_code : 6;
+ __u8 page_length;
+ __u8 reserved2 : 1;
+ __u8 bufe : 1;
+ __u8 ls_v : 1;
+ __u8 test_write : 1;
+ __u8 write_type : 4;
+ __u8 multi_session : 2; /* or border, DVD */
+ __u8 fp : 1;
+ __u8 copy : 1;
+ __u8 track_mode : 4;
+ __u8 reserved3 : 4;
+ __u8 data_block_type : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 page_code : 6;
+ __u8 reserved1 : 1;
+ __u8 ps : 1;
+ __u8 page_length;
+ __u8 write_type : 4;
+ __u8 test_write : 1;
+ __u8 ls_v : 1;
+ __u8 bufe : 1;
+ __u8 reserved2 : 1;
+ __u8 track_mode : 4;
+ __u8 copy : 1;
+ __u8 fp : 1;
+ __u8 multi_session : 2; /* or border, DVD */
+ __u8 data_block_type : 4;
+ __u8 reserved3 : 4;
+#endif
+ __u8 link_size;
+ __u8 reserved4;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved5 : 2;
+ __u8 app_code : 6;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 app_code : 6;
+ __u8 reserved5 : 2;
+#endif
+ __u8 session_format;
+ __u8 reserved6;
+ __u32 packet_size;
+ __u16 audio_pause;
+ __u8 mcn[16];
+ __u8 isrc[16];
+ __u8 subhdr0;
+ __u8 subhdr1;
+ __u8 subhdr2;
+ __u8 subhdr3;
+} write_param_page __attribute__((packed));
+
#endif /* End of kernel only stuff */
#endif /* _LINUX_CDROM_H */
extern void iput(struct inode *);
extern struct inode * igrab(struct inode *);
extern ino_t iunique(struct super_block *, ino_t);
-extern struct inode * iget(struct super_block *, unsigned long);
+
+typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+static inline struct inode *iget(struct super_block *sb, unsigned long ino)
+{
+ return iget4(sb, ino, NULL, NULL);
+}
+
extern void clear_inode(struct inode *);
extern struct inode * get_empty_inode(void);
#define WIN_SRST 0x08 /* ATAPI soft reset command */
#define WIN_PACKETCMD 0xa0 /* Send a packet command. */
+#define EXABYTE_ENABLE_NEST 0xf0
+
/* WIN_SMART sub-commands */
#define SMART_READ_VALUES 0xd0
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 */
+ unsigned long timeout; /* max time to wait for irq */
special_t special; /* special action flags */
byte keep_settings; /* restore settings after drive reset */
byte using_dma; /* disk is using dma for read/write */
* This is used to provide support for strange interfaces
*/
typedef void (ide_selectproc_t) (ide_drive_t *);
+typedef void (ide_resetproc_t) (ide_drive_t *);
/*
* hwif_chipset_t is used to keep track of the specific hardware
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_resetproc_t *resetproc; /* routine to reset controller after a disk reset */
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 */
* 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);
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler);
/*
* Error reporting, in human readable form (luxurious, but a memory hog).
#define pgcache_under_min() (atomic_read(&page_cache_size) * 100 < \
page_cache.min_percent * num_physpages)
+#define vmlist_access_lock(mm) spin_lock(&mm->page_table_lock)
+#define vmlist_access_unlock(mm) spin_unlock(&mm->page_table_lock)
+#define vmlist_modify_lock(mm) vmlist_access_lock(mm)
+#define vmlist_modify_unlock(mm) vmlist_access_unlock(mm)
+
+
#endif /* __KERNEL__ */
#endif
struct nfs_time ctime;
};
-struct nfs_sattr {
- __u32 mode;
- __u32 uid;
- __u32 gid;
- __u32 size;
- struct nfs_time atime;
- struct nfs_time mtime;
-};
-
struct nfs_fsinfo {
__u32 tsize;
__u32 bsize;
struct nfs_sattrargs {
struct nfs_fh * fh;
- struct nfs_sattr * sattr;
+ struct iattr * sattr;
};
struct nfs_diropargs {
struct nfs_createargs {
struct nfs_fh * fh;
const char * name;
- struct nfs_sattr * sattr;
+ struct iattr * sattr;
};
struct nfs_renameargs {
struct nfs_fh * fromfh;
const char * fromname;
const char * topath;
- struct nfs_sattr * sattr;
+ struct iattr * sattr;
};
struct nfs_readdirargs {
: NFS_SERVER(inode)->acregmax)
#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
-#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATE)
+#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
#define NFS_WRITEBACK(inode) ((inode)->u.nfs_i.writeback)
#define NFS_COOKIES(inode) ((inode)->u.nfs_i.cookies)
#define NFS_DIREOF(inode) ((inode)->u.nfs_i.direof)
+#define NFS_FILEID(inode) ((inode)->u.nfs_i.fileid)
+#define NFS_FSID(inode) ((inode)->u.nfs_i.fsid)
+
/*
* These are the default flags for swap requests
*/
extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr);
extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_sattr *sattr, struct nfs_fattr *fattr);
+ struct nfs_fattr *fattr, struct iattr *sattr);
extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
const char *name, struct nfs_fh *fhandle,
struct nfs_fattr *fattr);
int swap, unsigned long offset, unsigned int count,
const void *buffer, struct nfs_fattr *fattr);
extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_sattr *sattr,
+ const char *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr);
extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
const char *name);
struct nfs_fh *dir, const char *name);
extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
const char *name, const char *path,
- struct nfs_sattr *sattr);
+ struct iattr *sattr);
extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_sattr *sattr,
+ const char *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr);
extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
const char *name);
*/
extern struct super_block *nfs_read_super(struct super_block *, void *, int);
extern int init_nfs_fs(void);
+extern void nfs_zap_caches(struct inode *);
extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
struct nfs_fattr *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_revalidate(struct dentry *);
extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
-extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *);
+extern int __nfs_revalidate_inode(struct nfs_server *, struct dentry *);
/*
* linux/fs/nfs/file.c
nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
+ if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
return 0;
- return _nfs_revalidate_inode(server, dentry);
+ return __nfs_revalidate_inode(server, dentry);
}
/* NFS root */
* nfs fs inode data in memory
*/
struct nfs_inode_info {
+ /*
+ * The 64bit 'inode number'
+ */
+ __u32 fsid;
+ __u32 fileid;
+
/*
* Various flags
*/
/*
* Legal inode flag values
*/
-#define NFS_INO_REVALIDATE 0x0001 /* revalidating attrs */
+#define NFS_INO_REVALIDATING 0x0001 /* revalidating attrs */
#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */
/*
return 0;
}
+extern struct proc_dir_entry proc_root;
#endif /* CONFIG_PROC_FS */
struct signal_queue *sigqueue, **sigqueue_tail;
unsigned long sas_ss_sp;
size_t sas_ss_size;
+
+/* Thread group tracking */
+ u32 parent_exec_id;
+ u32 self_exec_id;
};
/*
/* files */ &init_files, \
/* mm */ NULL, &init_mm, \
/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
+/* exec cts */ 0,0,0, \
}
#ifndef INIT_TASK_SIZE
extern void sysv_free_block(struct super_block * sb, unsigned int block);
extern unsigned long sysv_count_free_blocks(struct super_block *sb);
-extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
extern int sysv_get_block(struct inode *, long, struct buffer_head *, int);
extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
extern int sysctl_local_port_range[2];
+#ifdef CONFIG_INET
extern __inline__ int ip_send(struct sk_buff *skb)
{
if (skb->len > skb->dst->pmtu)
buf[3]=addr&0x7F;
}
+#endif
extern int ip_call_ra_chain(struct sk_buff *skb);
#include <linux/isapnp.h>
#endif
+#ifdef CONFIG_IRDA
+#include <net/irda/irda_device.h>
+#endif
+
/*
* Versions of gcc older than that listed below may actually compile
* and link okay, but the end product can have subtle run time bugs.
> (unsigned long) current->rlim[RLIMIT_AS].rlim_cur)
return -ENOMEM;
current->mm->total_vm += tmp >> PAGE_SHIFT;
+ vmlist_modify_lock(current->mm);
insert_vm_struct(current->mm, shmd);
merge_segments(current->mm, shmd->vm_start, shmd->vm_end);
+ vmlist_modify_unlock(current->mm);
return 0;
}
read_lock(&tasklist_lock);
for_each_task(p) {
if (p->p_opptr == father) {
+ /* We dont want people slaying init */
p->exit_signal = SIGCHLD;
+ p->self_exec_id++;
p->p_opptr = child_reaper; /* init */
if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
}
*/
static void exit_notify(void)
{
- struct task_struct * p;
+ struct task_struct * p, *t;
forget_original_parent(current);
/*
* and we were the only connection outside, so our pgrp
* is about to become orphaned.
*/
- if ((current->p_pptr->pgrp != current->pgrp) &&
- (current->p_pptr->session == current->session) &&
+
+ t = current->p_pptr;
+
+ if ((t->pgrp != current->pgrp) &&
+ (t->session == current->session) &&
will_become_orphaned_pgrp(current->pgrp, current) &&
has_stopped_jobs(current->pgrp)) {
kill_pg(current->pgrp,SIGHUP,1);
kill_pg(current->pgrp,SIGCONT,1);
}
- /* Let father know we died */
+ /* Let father know we died
+ *
+ * Thread signals are configurable, but you aren't going to use
+ * that to send signals to arbitary processes.
+ * That stops right now.
+ *
+ * If the parent exec id doesn't match the exec id we saved
+ * when we started then we know the parent has changed security
+ * domain.
+ *
+ * If our self_exec id doesn't match our parent_exec_id then
+ * we have changed execution domain as these two values started
+ * the same after a fork.
+ *
+ */
+
+ if(current->exit_signal != SIGCHLD &&
+ ( current->parent_exec_id != t->self_exec_id ||
+ current->self_exec_id != current->parent_exec_id)
+ && !capable(CAP_KILL))
+ current->exit_signal = SIGCHLD;
+
notify_parent(current, current->exit_signal);
/*
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
/* The idle threads do not count.. */
int nr_threads=0;
if (retval)
goto bad_fork_cleanup_sighand;
p->semundo = NULL;
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+
+ p->parent_exec_id = p->self_exec_id;
/* ok, now we should be set up.. */
p->swappable = 1;
EXPORT_SYMBOL(_fput);
EXPORT_SYMBOL(igrab);
EXPORT_SYMBOL(iunique);
-EXPORT_SYMBOL(iget);
+EXPORT_SYMBOL(iget4);
EXPORT_SYMBOL(iput);
EXPORT_SYMBOL(__namei);
EXPORT_SYMBOL(lookup_dentry);
int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
{
int copied;
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return 0;
+ struct vm_area_struct * vma;
down(&tsk->mm->mmap_sem);
+ vma = find_extend_vma(tsk, addr);
+ if (!vma) {
+ up(&tsk->mm->mmap_sem);
+ return 0;
+ }
copied = 0;
for (;;) {
unsigned long offset = addr & ~PAGE_MASK;
do_get_fast_time(t);
}
+/* The xtime_lock is not only serializing the xtime read/writes but it's also
+ serializing all accesses to the global NTP variables now. */
+extern rwlock_t xtime_lock;
+
#if !defined(__alpha__) && !defined(__ia64__)
/*
return -EPERM;
if (get_user(value, tptr))
return -EFAULT;
- cli();
+ write_lock_irq(&xtime_lock);
xtime.tv_sec = value;
xtime.tv_usec = 0;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+ write_unlock_irq(&xtime_lock);
return 0;
}
*/
inline static void warp_clock(void)
{
- cli();
+ write_lock_irq(&xtime_lock);
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
- sti();
+ write_unlock_irq(&xtime_lock);
}
/*
int do_adjtimex(struct timex *txc)
{
long ltemp, mtemp, save_adjust;
- int result = time_state; /* mostly `TIME_OK' */
+ int result;
/* In order to modify anything, you gotta be super-user! */
if (txc->modes && !capable(CAP_SYS_TIME))
if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
return -EINVAL;
- cli(); /* SMP: global cli() is enough protection. */
+ write_lock_irq(&xtime_lock);
+ result = time_state; /* mostly `TIME_OK' */
/* Save for later - semantics of adjtime is to return old value */
save_adjust = time_adjust;
txc->constant = time_constant;
txc->precision = time_precision;
txc->tolerance = time_tolerance;
- do_gettimeofday(&txc->time);
txc->tick = tick;
txc->ppsfreq = pps_freq;
txc->jitter = pps_jitter >> PPS_AVG;
txc->calcnt = pps_calcnt;
txc->errcnt = pps_errcnt;
txc->stbcnt = pps_stbcnt;
-
- sti();
+ write_unlock_irq(&xtime_lock);
+ do_gettimeofday(&txc->time);
return(result);
}
static inline int mlock_fixup_all(struct vm_area_struct * vma, int newflags)
{
+ vmlist_modify_lock(vma->vm_mm);
vma->vm_flags = newflags;
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
if (!n)
return -EAGAIN;
*n = *vma;
- vma->vm_start = end;
n->vm_end = end;
- vma->vm_offset += vma->vm_start - n->vm_start;
n->vm_flags = newflags;
if (n->vm_file)
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ vmlist_modify_lock(vma->vm_mm);
+ vma->vm_offset += end - vma->vm_start;
+ vma->vm_start = end;
insert_vm_struct(current->mm, n);
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
if (!n)
return -EAGAIN;
*n = *vma;
- vma->vm_end = start;
n->vm_start = start;
n->vm_offset += n->vm_start - vma->vm_start;
n->vm_flags = newflags;
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ vmlist_modify_lock(vma->vm_mm);
+ vma->vm_end = start;
insert_vm_struct(current->mm, n);
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
*left = *vma;
*right = *vma;
left->vm_end = start;
- vma->vm_start = start;
- vma->vm_end = end;
right->vm_start = end;
- vma->vm_offset += vma->vm_start - left->vm_start;
right->vm_offset += right->vm_start - left->vm_start;
vma->vm_flags = newflags;
if (vma->vm_file)
vma->vm_ops->open(left);
vma->vm_ops->open(right);
}
+ vmlist_modify_lock(vma->vm_mm);
+ vma->vm_offset += start - vma->vm_start;
+ vma->vm_start = start;
+ vma->vm_end = end;
+ vma->vm_flags = newflags;
insert_vm_struct(current->mm, left);
insert_vm_struct(current->mm, right);
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
break;
}
}
+ vmlist_modify_lock(current->mm);
merge_segments(current->mm, start, end);
+ vmlist_modify_unlock(current->mm);
return error;
}
if (error)
break;
}
+ vmlist_modify_lock(current->mm);
merge_segments(current->mm, 0, TASK_SIZE);
+ vmlist_modify_unlock(current->mm);
return error;
}
*/
flags = vma->vm_flags;
addr = vma->vm_start; /* can addr have changed?? */
+ vmlist_modify_lock(mm);
insert_vm_struct(mm, vma);
merge_segments(mm, vma->vm_start, vma->vm_end);
+ vmlist_modify_unlock(mm);
mm->total_vm += len >> PAGE_SHIFT;
if (flags & VM_LOCKED) {
}
/* Work out to one of the ends. */
- if (end == area->vm_end)
+ if (end == area->vm_end) {
area->vm_end = addr;
- else if (addr == area->vm_start) {
+ vmlist_modify_lock(current->mm);
+ } else if (addr == area->vm_start) {
area->vm_offset += (end - area->vm_start);
area->vm_start = end;
+ vmlist_modify_lock(current->mm);
} else {
/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
/* Add end mapping -- leave beginning for below */
if (mpnt->vm_ops && mpnt->vm_ops->open)
mpnt->vm_ops->open(mpnt);
area->vm_end = addr; /* Truncate area */
+ vmlist_modify_lock(current->mm);
insert_vm_struct(current->mm, mpnt);
}
insert_vm_struct(current->mm, area);
+ vmlist_modify_unlock(current->mm);
return extra;
}
npp = (prev ? &prev->vm_next : &mm->mmap);
free = NULL;
+ vmlist_modify_lock(mm);
for ( ; mpnt && mpnt->vm_start < addr+len; mpnt = *npp) {
*npp = mpnt->vm_next;
mpnt->vm_next = free;
if (mm->mmap_avl)
avl_remove(mpnt, &mm->mmap_avl);
}
+ mm->mmap_cache = NULL; /* Kill the cache. */
+ vmlist_modify_unlock(mm);
/* Ok - we have the memory areas we should free on the 'free' list,
* so release them, and unmap the page range..
end = end > mpnt->vm_end ? mpnt->vm_end : end;
size = end - st;
+ /*
+ * The lock_kernel interlocks with kswapd try_to_swap_out
+ * invoking a driver swapout() method, and being able to
+ * guarantee vma existance.
+ */
lock_kernel();
if (mpnt->vm_ops && mpnt->vm_ops->unmap)
mpnt->vm_ops->unmap(mpnt, st, size);
free_pgtables(mm, prev, addr, addr+len);
- mm->mmap_cache = NULL; /* Kill the cache. */
return 0;
}
flags = vma->vm_flags;
addr = vma->vm_start;
+ vmlist_modify_lock(mm);
insert_vm_struct(mm, vma);
merge_segments(mm, vma->vm_start, vma->vm_end);
+ vmlist_modify_unlock(mm);
mm->total_vm += len >> PAGE_SHIFT;
if (flags & VM_LOCKED) {
release_segments(mm);
mpnt = mm->mmap;
+ vmlist_modify_lock(mm);
mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
+ vmlist_modify_unlock(mm);
mm->rss = 0;
mm->total_vm = 0;
mm->locked_vm = 0;
prev = mpnt;
mpnt = mpnt->vm_next;
}
+ mm->mmap_cache = NULL; /* Kill the cache. */
/* prev and mpnt cycle through the list, as long as
* start_addr < mpnt->vm_end && prev->vm_start < end_addr
if (mpnt->vm_ops && mpnt->vm_ops->close) {
mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
mpnt->vm_start = mpnt->vm_end;
+ vmlist_modify_unlock(mm);
mpnt->vm_ops->close(mpnt);
+ vmlist_modify_lock(mm);
}
mm->map_count--;
remove_shared_vm_struct(mpnt);
kmem_cache_free(vm_area_cachep, mpnt);
mpnt = prev;
}
- mm->mmap_cache = NULL; /* Kill the cache. */
}
void __init vma_init(void)
static inline int mprotect_fixup_all(struct vm_area_struct * vma,
int newflags, pgprot_t prot)
{
+ vmlist_modify_lock(vma->vm_mm);
vma->vm_flags = newflags;
vma->vm_page_prot = prot;
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
if (!n)
return -ENOMEM;
*n = *vma;
- vma->vm_start = end;
n->vm_end = end;
- vma->vm_offset += vma->vm_start - n->vm_start;
n->vm_flags = newflags;
n->vm_page_prot = prot;
if (n->vm_file)
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ vmlist_modify_lock(vma->vm_mm);
+ vma->vm_offset += end - vma->vm_start;
+ vma->vm_start = end;
insert_vm_struct(current->mm, n);
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
if (!n)
return -ENOMEM;
*n = *vma;
- vma->vm_end = start;
n->vm_start = start;
n->vm_offset += n->vm_start - vma->vm_start;
n->vm_flags = newflags;
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ vmlist_modify_lock(vma->vm_mm);
+ vma->vm_end = start;
insert_vm_struct(current->mm, n);
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
*left = *vma;
*right = *vma;
left->vm_end = start;
- vma->vm_start = start;
- vma->vm_end = end;
right->vm_start = end;
- vma->vm_offset += vma->vm_start - left->vm_start;
right->vm_offset += right->vm_start - left->vm_start;
- vma->vm_flags = newflags;
- vma->vm_page_prot = prot;
if (vma->vm_file)
atomic_add(2,&vma->vm_file->f_count);
if (vma->vm_ops && vma->vm_ops->open) {
vma->vm_ops->open(left);
vma->vm_ops->open(right);
}
+ vmlist_modify_lock(vma->vm_mm);
+ vma->vm_offset += start - vma->vm_start;
+ vma->vm_start = start;
+ vma->vm_end = end;
+ vma->vm_flags = newflags;
+ vma->vm_page_prot = prot;
insert_vm_struct(current->mm, left);
insert_vm_struct(current->mm, right);
+ vmlist_modify_unlock(vma->vm_mm);
return 0;
}
break;
}
}
+ vmlist_modify_lock(current->mm);
merge_segments(current->mm, start, end);
+ vmlist_modify_unlock(current->mm);
out:
up(¤t->mm->mmap_sem);
return error;
get_file(new_vma->vm_file);
if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma);
+ vmlist_modify_lock(current->mm);
insert_vm_struct(current->mm, new_vma);
merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
+ vmlist_modify_unlock(vma->vm_mm);
do_munmap(addr, old_len);
current->mm->total_vm += new_len >> PAGE_SHIFT;
if (new_vma->vm_flags & VM_LOCKED) {
/* can we just expand the current mapping? */
if (max_addr - addr >= new_len) {
int pages = (new_len - old_len) >> PAGE_SHIFT;
+ vmlist_modify_lock(vma->vm_mm);
vma->vm_end = addr + new_len;
+ vmlist_modify_unlock(vma->vm_mm);
current->mm->total_vm += pages;
if (vma->vm_flags & VM_LOCKED) {
current->mm->locked_vm += pages;
goto out_failed;
page = mem_map + MAP_NR(page_addr);
- spin_lock(&vma->vm_mm->page_table_lock);
- if (pte_val(pte) != pte_val(*page_table))
- goto out_failed_unlock;
/* Don't look at this pte if it's been accessed recently. */
if (pte_young(pte)) {
*/
set_pte(page_table, pte_mkold(pte));
set_bit(PG_referenced, &page->flags);
- goto out_failed_unlock;
+ goto out_failed;
}
if (PageReserved(page)
|| PageLocked(page)
|| ((gfp_mask & __GFP_DMA) && !PageDMA(page))
|| (!(gfp_mask & __GFP_BIGMEM) && PageBIGMEM(page)))
- goto out_failed_unlock;
+ goto out_failed;
/*
* Is the page already in the swap cache? If so, then
vma->vm_mm->rss--;
flush_tlb_page(vma, address);
__free_page(page);
- goto out_failed_unlock;
+ goto out_failed;
}
/*
* locks etc.
*/
if (!(gfp_mask & __GFP_IO))
- goto out_failed_unlock;
+ goto out_failed;
/*
* Ok, it's really dirty. That means that
if (vma->vm_ops && vma->vm_ops->swapout) {
int error;
pte_clear(page_table);
- spin_unlock(&vma->vm_mm->page_table_lock);
- flush_tlb_page(vma, address);
vma->vm_mm->rss--;
+ flush_tlb_page(vma, address);
+ vmlist_access_unlock(vma->vm_mm);
error = vma->vm_ops->swapout(vma, page);
if (!error)
goto out_free_success;
*/
entry = acquire_swap_entry(page);
if (!entry)
- goto out_failed_unlock; /* No swap space left */
+ goto out_failed; /* No swap space left */
if (!(page = prepare_bigmem_swapout(page)))
- goto out_swap_free_unlock;
+ goto out_swap_free;
vma->vm_mm->rss--;
set_pte(page_table, __pte(entry));
- spin_unlock(&vma->vm_mm->page_table_lock);
+ vmlist_access_unlock(vma->vm_mm);
flush_tlb_page(vma, address);
swap_duplicate(entry); /* One for the process, one for the swap cache */
out_free_success:
__free_page(page);
return 1;
-out_failed_unlock:
- spin_unlock(&vma->vm_mm->page_table_lock);
-out_failed:
- return 0;
-out_swap_free_unlock:
+out_swap_free:
swap_free(entry);
- spin_unlock(&vma->vm_mm->page_table_lock);
+out_failed:
return 0;
}
address = mm->swap_address;
/*
- * Find the proper vm-area
+ * Find the proper vm-area after freezing the vma chain
+ * and ptes.
*/
+ vmlist_access_lock(mm);
vma = find_vma(mm, address);
if (vma) {
if (address < vma->vm_start)
address = vma->vm_start;
}
}
+ vmlist_access_unlock(mm);
/* We didn't find anything for the process */
mm->swap_cnt = 0;
*
*/
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
dst_release(skb->dst);
if(skb->destructor)
skb->destructor(skb);
+#ifdef CONFIG_NET
if(skb->rx_dev)
dev_put(skb->rx_dev);
+#endif
skb_headerinit(skb, NULL, 0); /* clean state */
kfree_skbmem(skb);
}
#include <net/ipv6.h>
#include <net/inet_common.h>
-#include <asm/segment.h>
-
#include <linux/inet.h>
#include <linux/stddef.h>
req->rq_rvec[0].iov_len = bufsiz;
req->rq_rlen = bufsiz;
req->rq_rnr = 1;
+ req->rq_damaged = 0;
if (task->tk_proc > clnt->cl_maxproc) {
printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
return;
}
+ /* Zero buffer so we have automatic zero-padding of opaque & string */
+ memset(task->tk_buffer, 0, bufsiz);
+
/* Encode header and provided arguments */
encode = rpcproc_encode(clnt, task->tk_proc);
if (!(p = call_header(task))) {
static u32 swap_buffer[PAGE_SIZE >> 2];
static int swap_buffer_used = 0;
+/*
+ * Make allocation of the swap_buffer SMP-safe
+ */
+static __inline__ int rpc_lock_swapbuf(void)
+{
+ return !test_and_set_bit(1, &swap_buffer_used);
+}
+static __inline__ void rpc_unlock_swapbuf(void)
+{
+ clear_bit(1, &swap_buffer_used);
+}
+
/*
* Spinlock for wait queues. Access to the latter also has to be
* interrupt-safe in order to allow timers to wake up sleeping tasks.
dprintk("RPC: allocated buffer %p\n", buffer);
return buffer;
}
- if ((flags & RPC_TASK_SWAPPER) && !swap_buffer_used++) {
+ if ((flags & RPC_TASK_SWAPPER) && size <= sizeof(swap_buffer)
+ && rpc_lock_swapbuf()) {
dprintk("RPC: used last-ditch swap buffer\n");
return swap_buffer;
}
kfree(buffer);
return;
}
- swap_buffer_used = 0;
+ rpc_unlock_swapbuf();
}
/*