GEMS Kernel is going to be better than ever...
WOO HOO!
This commit is contained in:
parent
3cd3f0482b
commit
58217f5900
737 changed files with 208803 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
opt/**
|
||||
builds/**
|
3
BUGS.md
Normal file
3
BUGS.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
Finally! *we boot!* But that doesn't mean we are bug free!
|
||||
|
||||
See TODO.md for details.
|
19
COC.md
Normal file
19
COC.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Sparksammy Code of Conduct 1.025
|
||||
We, overall, must follow one simple rule to each other: *Stay excellent to each other.* This includes but is not limited to:
|
||||
* Using welcoming behavior and language.
|
||||
* Do not cuss or use bad language unless you feel strongly about a subject
|
||||
* Basically: Do not abuse bad language
|
||||
* No sexual behavior unless approved by the other person.
|
||||
* *Digital/Virtual hugs do not count.*
|
||||
* Speaking English is a requirement so everyone understands each other.
|
||||
* No DOXing
|
||||
* No murderers and sexual predators that haven't done jail time yet are allowed here. Move on to another project.
|
||||
* Samuel (Sparksammy) Lord can do whatever he wants.
|
||||
* This is just so that the owner (Samuel Lord) never gets kicked or banned from his own project[s].
|
||||
* "The only way to do great work is to love what you do." --Steve Jobs
|
||||
|
||||
## About real names.
|
||||
If you are comfortable going by your real name, that's great! If not, just go by your GitHub username. *If a user does not feel comfortable using their real name, don't use their real name.*
|
||||
|
||||
## About punishments.
|
||||
If you get punished, your punishment will be decided depending on severity of the damage and/or what you did. For example: If you say a curse word that's uncalled for, you will be warned 3 times then kicked. But if you are a murderer and didn't go to jail, you are banned until you go to jail and your sentence is up.
|
20
LICENSE-GEMS-CODE
Normal file
20
LICENSE-GEMS-CODE
Normal file
|
@ -0,0 +1,20 @@
|
|||
The Samuel Public License Revision 5 (SPL-R5)
|
||||
|
||||
Copyright (c) 2024 Sneed Group
|
||||
|
||||
This document grants permission, without charge, to any individual acquiring a copy of the software and its associated documentation files (hereinafter referred to as the "Software"). Such individuals are authorized to engage in activities related to the Software with certain restrictions (listed below), including, but not limited to, the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software. These permissions extend to persons to whom the Software is furnished, subject to compliance with the specified conditions outlined below.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
In making contributions to the Software, contributors irrevocably assign, transfer, and convey all rights, titles, and interests in and to their contributions to the project owner(s). This assignment is absolute and encompasses all intellectual property rights, including, but not limited to, copyrights, patents, trademarks, and trade secrets. Contributors acknowledge and consent that they have no further claim, right, or interest in their contributions and agree to relinquish any moral rights associated with the contributed content. This assignment is effective upon the act of contributing to the Software, and contributors affirm that they have the authority to make such an assignment. However, contributors retain the right to modify their contributions.
|
||||
|
||||
Furthermore, this document permits the reuse and redistribution of both executable binaries and source code, contingent upon the inclusion of the previously mentioned copyright notice and permission notice in all copies or substantial portions of the Software. It is imperative that you explicitly acknowledge and agree that the owner(s) retain ownership rights over the aforementioned source code.
|
||||
|
||||
Moreover, companies using the Software are encouraged to contribute upstream. Fortune 500 companies are required to make an annual contribution of at least 20,000 USD or an equivalent amount to support the project's sustainability unless no donation option is provided.
|
||||
|
||||
Additionally, note that the use of AI-assisted tools, including but not limited to GitHub Copilot and ChatGPT, is expressly permitted in conjunction with this software. Users are encouraged to leverage these AI tools to enhance their experience in developing, modifying, and interacting with the Software. The permission granted herein extends to the integration and utilization of AI-generated content for coding and communication purposes. The owners(s) of the Software acknowledge and embrace the collaborative nature of AI-assisted development.
|
||||
|
||||
In addition, the owner of the code is granted the authority to update their copy of The Samuel Public License (SPL) to the latest revision. This update may be undertaken at the discretion of the owner to ensure alignment with any subsequent revisions made to The Samuel Public License.
|
||||
|
||||
The aforementioned copyright notice and this permission notice must be included in all copies or substantial portions of the Software.
|
||||
|
6
LICENSE.md
Normal file
6
LICENSE.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# About licensing...
|
||||
|
||||
GEMS Kernel is a cross-licensed project. Here's how it works:
|
||||
|
||||
* GEMS Kernel's own code is covered under "LICENSE-GEMS-CODE"
|
||||
* Everything in the "THIRDPARTY" folder is covered under it's respective licenses
|
12
NOTES.md
Normal file
12
NOTES.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
Here are all the notes so far:
|
||||
|
||||
|
||||
http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm
|
||||
this link is useful since it teaches you how to call lua from a running C program by using lua libraries
|
||||
(PS: Do not use GNU Linker if you run lua in c, however for technical reasons most OSDev Kernels/OSes (including ours) require ld, so we can no longer use LUA..)
|
||||
|
||||
You can't make LUA in C bootable. :-(
|
||||
|
||||
Seeking outside the file? Try changing linker.ld and changing your bootloader to start.s! Modify accordingly.
|
||||
|
||||
*You really do need a i686 cross-compiler, get one here: https://drive.google.com/file/d/0Bw6lG3Ej2746STJaM2dNbC05elE/view?usp=sharing*
|
6
OLD/bl1.asm
Normal file
6
OLD/bl1.asm
Normal file
|
@ -0,0 +1,6 @@
|
|||
;BL.asm files are deprecated, please use booloader.asm
|
||||
mov ax, 9ch
|
||||
mov ss, ax ;cannot be written directly
|
||||
mov sp, 4094d
|
||||
mov ax, 7c0h
|
||||
mov ds, ax ;cannot be written directly
|
8
OLD/bl2.asm
Normal file
8
OLD/bl2.asm
Normal file
|
@ -0,0 +1,8 @@
|
|||
;BL.asm files are deprecated, please use booloader.asm
|
||||
quit:
|
||||
hlt
|
||||
jmp quit
|
||||
jmp $
|
||||
times 510-($-$$) db 0
|
||||
dw 0xAA55
|
||||
|
43
OLD/micro.lua
Normal file
43
OLD/micro.lua
Normal file
|
@ -0,0 +1,43 @@
|
|||
--NOTE TO DEVS:
|
||||
--THESE LUA FILES ARE DEPRECATED..
|
||||
--USE RUSHELL.H INSTEAD...
|
||||
fn = ""
|
||||
file = ""
|
||||
_G.buffer = ""
|
||||
exitmicro = false
|
||||
function wait(s)
|
||||
local ntime = os.time() + s
|
||||
repeat until os.time() > ntime
|
||||
end
|
||||
|
||||
function save(file)
|
||||
_G[fn] = _G.buffer
|
||||
end
|
||||
|
||||
function try(code)
|
||||
if code == "::clear" then
|
||||
_G.buffer = ""
|
||||
io.write("Clear OK");
|
||||
elseif code == "::exit" then
|
||||
exitmicro = true
|
||||
io.write("Exit OK");
|
||||
else
|
||||
_G.buffer = _G.buffer .. "\n" .. line
|
||||
end
|
||||
end
|
||||
|
||||
io.write("File name:");
|
||||
fn = io.read("*l");
|
||||
|
||||
if _G[fn] ~= nil then
|
||||
_G.buffer = _G[fn]
|
||||
else
|
||||
_G.buffer = ""
|
||||
end
|
||||
while exitmicro == false do
|
||||
io.write("->");
|
||||
line = io.read("*l");
|
||||
try(line);
|
||||
save(fn)
|
||||
end
|
||||
print(_G[fn]);
|
139
OLD/os.lua
Normal file
139
OLD/os.lua
Normal file
|
@ -0,0 +1,139 @@
|
|||
--NOTE TO DEVS:
|
||||
--THESE LUA FILES ARE DEPRECATED..
|
||||
--USE RUSHELL.H INSTEAD...
|
||||
args = {}
|
||||
ver = "0.721 - DIY App Update!"
|
||||
|
||||
--UDP packet send code begin
|
||||
function sendPacket(rec, cont)
|
||||
local socket = require("socket")
|
||||
local udp = assert(socket.udp())
|
||||
local data
|
||||
|
||||
udp:settimeout(1)
|
||||
assert(udp:setsockname("*",0))
|
||||
assert(udp:setpeername(rec,1234))
|
||||
|
||||
for i = 0, 2, 1 do
|
||||
assert(udp:send(cont))
|
||||
data = udp:receive()
|
||||
if data then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if data == nil then
|
||||
print("timeout")
|
||||
else
|
||||
print(data)
|
||||
end
|
||||
end
|
||||
--End of socket code
|
||||
|
||||
function wait(s)
|
||||
local ntime = os.time() + s
|
||||
repeat until os.time() > ntime
|
||||
end
|
||||
|
||||
function clear()
|
||||
for i = 1,26 do
|
||||
print("\n\n")
|
||||
end
|
||||
end
|
||||
|
||||
function dog(fn)
|
||||
io.write(_G[fn] .. "\n");
|
||||
end
|
||||
|
||||
function lf(fn)
|
||||
assert(loadstring(_G[fn] .. "\n"))();
|
||||
end
|
||||
|
||||
function rushell(code)
|
||||
if string.find(_G.cmd, "print") then
|
||||
io.write(string.gsub(_G.cmd, "print " , "") .. "\n")
|
||||
elseif _G.cmd == "version" then
|
||||
io.write("Rushell version " .. ver .. " Beta\n");
|
||||
elseif _G.cmd == "help" then
|
||||
io.write("There are seven commands:\n");
|
||||
io.write("print - Prints to the console - Usage: print hello world\n");
|
||||
io.write("version - prints the version - Usage: version\n");
|
||||
io.write("help - lists all the different commands - Usage: help\n");
|
||||
io.write("clear - clears the screen (not perfect) - Usage: clear\n");
|
||||
io.write("about - About rushell. - Usage: about\n");
|
||||
io.write("prompt - Waits until the user presses any key.\n");
|
||||
io.write("dog - cat alternative\n");
|
||||
io.write("micro - auto-saving text editor\n");
|
||||
elseif _G.cmd == "clear" then
|
||||
clear();
|
||||
elseif _G.cmd == "about" then
|
||||
io.write('Rushell is a small shell/scripting language for the GEMS OS.\n');
|
||||
elseif _G.cmd == "wait" then
|
||||
wait(args[1]);
|
||||
elseif _G.cmd == "prompt" then
|
||||
io.write("Press any key to continue");
|
||||
io.read("*l");
|
||||
elseif string.find(_G.cmd, "loadfile") then
|
||||
lf(string.gsub(_G.cmd, "loadfile ", ""))
|
||||
elseif string.find(_G.cmd, "loadstring") then
|
||||
assert(loadstring(string.gsub(_G.cmd, "loadstring ", "")))();
|
||||
elseif _G.cmd == "micro" then
|
||||
fn = ""
|
||||
file = ""
|
||||
_G.buffer = ""
|
||||
exitmicro = false
|
||||
function wait(s)
|
||||
local ntime = os.time() + s
|
||||
repeat until os.time() > ntime
|
||||
end
|
||||
|
||||
function save(file)
|
||||
_G[fn] = _G.buffer
|
||||
end
|
||||
|
||||
function try(code)
|
||||
if code == "::clear" then
|
||||
_G.buffer = ""
|
||||
io.write("Clear OK");
|
||||
elseif code == "::exit" then
|
||||
exitmicro = true
|
||||
io.write("Exit OK");
|
||||
else
|
||||
_G.buffer = _G.buffer .. "\n" .. line
|
||||
end
|
||||
end
|
||||
|
||||
io.write("File name:");
|
||||
fn = io.read("*l");
|
||||
|
||||
if _G[fn] ~= nil then
|
||||
_G.buffer = _G[fn]
|
||||
else
|
||||
_G.buffer = ""
|
||||
end
|
||||
while exitmicro == false do
|
||||
io.write("->");
|
||||
line = io.read("*l");
|
||||
try(line);
|
||||
save(fn)
|
||||
end
|
||||
print(_G[fn]);
|
||||
elseif string.find(_G.cmd, "dog") then
|
||||
dog(string.gsub(_G.cmd, "dog ", ""))
|
||||
else
|
||||
io.write("Unknown command!" .. "\n")
|
||||
end
|
||||
args = {}
|
||||
|
||||
end
|
||||
|
||||
io.write("GEMS LOADED SUCCESSFULLY!\n");
|
||||
io.write("We didn't plan ahead but you can try the Rushell beta edition while we finish the OS.\n");
|
||||
io.write("Hello! Welcome to Rushell " .. ver .. " BETA\n");
|
||||
while true do
|
||||
io.write("Rushell> ")
|
||||
line = io.read("*l");
|
||||
cmd = string.lower(line)
|
||||
rushell(cmd);
|
||||
end
|
55
README.md
Normal file
55
README.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# <img src="gems.png" alt="Logo" width="5%"/> GEMS KERNEL
|
||||
|
||||
GEMS - GEMS is ESSENTIALLY MAYBE SPINEL
|
||||
*Note: This is not Spinel, we are just trying to be better. ;)*
|
||||
Note: GEMS is in *really early development*, and will probably be that way for ***quite a while.*** Note: This is highly based off of https://wiki.osdev.org/ and user Zesterer's Bare_Bones, however it is modified quite a bit to work for me.
|
||||
|
||||
Seriously... You can only boot to a small splash screen, you can't even type anything...
|
||||
|
||||
but it has Colors, Sounds, A panic system so it is definitely improving.
|
||||
|
||||
However, here are the dependencies (in ubuntu) in case you *want* to compile this
|
||||
|
||||
~~sudo apt install -y libc6-dev-i386 grub-common nasm gcc liblua5.1-0-dev liblua50:i386 liblua50-dev:i386 libc-dev:i386 linux-libc-dev:i386 libc6-dev:i386 qemu-system-i386 grub-pc-bin lua-socket xorriso gcc-9-multilib libc6-dev-i386 libc6-x32 gcc-multilib libc6-dev-x32 libc6-dev linux-libc-dev~~
|
||||
|
||||
Update: You might want to install these:
|
||||
```
|
||||
sudo apt install -y build-essential grub-common nasm gcc git qemu-system-x86 grub-pc-bin lua-socket xorriso gcc-10-multilib gcc-arm-none-eabi git nasm grub2
|
||||
```
|
||||
Oh and also: You really need an *i686 cross compiler,* I reccomend this one here for GNU/Linux (put it int the source directory): https://drive.google.com/file/d/0Bw6lG3Ej2746STJaM2dNbC05elE/view?usp=sharing
|
||||
|
||||
Or for macOS, run this brew command (requires homebrew)
|
||||
|
||||
```
|
||||
brew install i686-elf-gcc nasm llvm objconv
|
||||
```
|
||||
|
||||
To compile run:
|
||||
```
|
||||
cd source && ../build-with-iso.sh
|
||||
```
|
||||
|
||||
Or on a Mac:
|
||||
```
|
||||
cd source && ./build-mac.sh
|
||||
```
|
||||
|
||||
And then setup GRUB on macOS if you would wish to create an ISO, as explained here:
|
||||
https://wiki.osdev.org/GRUB_2#HDD_Image_Instructions_for_OS_X_users
|
||||
|
||||
~~(Hint, download LUA 5.0 source here: https://www.lua.org/ftp/lua-5.0.tar.gz)~~ Update: We are switching to mostly custom C/ASM
|
||||
|
||||
Oh and a quick warning: *Test.sh / Qemu's PC SPEAKER is VERY LOUD. You will want to turn down your volume.*
|
||||
|
||||
# Other files
|
||||
COC.md is the *old* Code of Conduct for historical purposes. Read the new one [here.](https://github.com/NodeMixaholic/NodeMixaholic-COC/blob/master/COC.md)
|
||||
|
||||
BUGS.md is for listing all the different bugs and their origins/source and status.
|
||||
|
||||
NOTES.md is for listing everything we have learned so far.
|
||||
|
||||
WSLHOWTO.MD is a tutorial on how to build and run GEMS in Windows.
|
||||
|
||||
## Note about Licensing...
|
||||
|
||||
THIRDPARTY software under the source/THIRDPARTY directory are under their own licenses, shown in their own directories, and not the main license.
|
9
TODO.md
Normal file
9
TODO.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# TODO
|
||||
## FROM GREATEST TO LEAST PRIORITY
|
||||
* Fix int2str
|
||||
* Get PS/2 keyboard support working
|
||||
* Convert keycodes to english characters according to standard en-US layout
|
||||
* Finish up RuShell
|
||||
* Fix the ugly identation at the rloadstring("welcomescreen"); and no... running clear(); twice doesn't fix it.
|
||||
|
||||
https://cdn.discordapp.com/attachments/708416737774665782/740362200744591440/bug.png
|
27
WSLHOWTO.MD
Normal file
27
WSLHOWTO.MD
Normal file
|
@ -0,0 +1,27 @@
|
|||
# How to build (and run) GEMS in WSL.
|
||||
|
||||
If you decided to switch to Windows like me and you want to develop GEMS then here is a tutorial on how to do so:
|
||||
|
||||
How to build:
|
||||
|
||||
Setup WSL 2.x (Select Ubuntu or Debian)
|
||||
|
||||
Install all of the packages
|
||||
|
||||
run ./build.sh
|
||||
|
||||
How to test:
|
||||
|
||||
Download QEMU for windows.
|
||||
|
||||
Copy the GEMS ISO to the QEMU folder
|
||||
|
||||
Then run "./qemu-system-x86_64.exe -soundhw pcspk -cdrom builds/gems.iso -m 1000"
|
||||
|
||||
There are probably other, better ways of running GEMS in windows.
|
||||
|
||||
Try VirtualBox but give it a lot of Memory.
|
||||
|
||||
Maybe change the PATH variable to the QEMU Folder.
|
||||
|
||||
and then just run the command in Powershell (Without ./ at the beginning)
|
24
build-macos.sh
Executable file
24
build-macos.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
echo "Setting target as 32bit ELF"
|
||||
export TARGET=i386-elf
|
||||
echo "Making directories"
|
||||
mkdir builds
|
||||
mkdir builds/blocks
|
||||
mkdir builds/iso
|
||||
mkdir builds/iso/boot
|
||||
mkdir builds/iso/boot/grub
|
||||
echo "Building bootloader"
|
||||
i686-elf-gcc -std=gnu99 -ffreestanding -g -c start.s -o builds/blocks/bl.o
|
||||
echo "Building basic keyboard support"
|
||||
nasm -f elf32 detect-kbinput.asm -o builds/blocks/detectkeys.o
|
||||
echo "Building time related stuff..."
|
||||
echo "Building OS"
|
||||
set disassembly-flavor intel
|
||||
i686-elf-gcc builds/blocks/bl.o builds/blocks/detectkeys.o os.c -w -g -ffreestanding -m32 -o builds/iso/gems.elf -I"/usr/include" -nostdlib
|
||||
echo "Creating GRUB config"
|
||||
echo "set default=0" > builds/iso/boot/grub/grub.cfg
|
||||
echo "set timeout=60" >> builds/iso/boot/grub/grub.cfg
|
||||
echo 'menuentry "GEMS" {' >> builds/iso/boot/grub/grub.cfg
|
||||
echo " multiboot /gems.elf" >> builds/iso/boot/grub/grub.cfg
|
||||
echo " boot" >> builds/iso/boot/grub/grub.cfg
|
||||
echo "}" >> builds/iso/boot/grub/grub.cfg
|
||||
echo "Note: NOT CREATING ISO. USE CREATE-ISO.SH TO DO THIS."
|
5
build-with-iso.sh
Executable file
5
build-with-iso.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
./build.sh
|
||||
echo "Creating ISO"
|
||||
bash ./create-iso.sh
|
||||
|
||||
|
24
build.sh
Executable file
24
build.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
echo "Setting target as 32bit ELF"
|
||||
export TARGET=i386-elf
|
||||
echo "Making directories"
|
||||
mkdir builds
|
||||
mkdir builds/blocks
|
||||
mkdir builds/iso
|
||||
mkdir builds/iso/boot
|
||||
mkdir builds/iso/boot/grub
|
||||
echo "Building bootloader"
|
||||
nasm -f elf32 source/bootloader.asm -o builds/blocks/bootloader.o
|
||||
echo "Building basic keyboard support"
|
||||
nasm -f elf32 source/detect-kbinput.asm -o builds/blocks/detectkeys.o
|
||||
echo "Building OS"
|
||||
set disassembly-flavor intel
|
||||
opt/cross/bin/i686-elf-gcc builds/blocks/bootloader.o -ffreestanding -nostdlib builds/blocks/detectkeys.o source/os.c -w -g -m32 -o builds/iso/gems.elf -I"/usr/include" -I"source/THIRDPARTY/lwext4-master/include/" -I"source/THIRDPARTY/linux-old/include/linux" -I"source/THIRDPARTY/linux-old/include/asm"
|
||||
echo "Creating GRUB config"
|
||||
echo "set default=0" > builds/iso/boot/grub/grub.cfg
|
||||
echo "set timeout=60" >> builds/iso/boot/grub/grub.cfg
|
||||
echo 'menuentry "GEMS" {' >> builds/iso/boot/grub/grub.cfg
|
||||
echo " multiboot /gems.elf" >> builds/iso/boot/grub/grub.cfg
|
||||
echo " boot" >> builds/iso/boot/grub/grub.cfg
|
||||
echo "}" >> builds/iso/boot/grub/grub.cfg
|
||||
echo "Creating ISO"
|
||||
echo "Note: NOT CREATING ISO. USE CREATE-ISO.SH TO DO THIS."
|
2
create-iso.sh
Executable file
2
create-iso.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
echo "Creating ISO"
|
||||
grub-mkrescue -d /usr/lib/grub/i386-pc -o builds/gems.iso builds/iso
|
BIN
gems.png
Normal file
BIN
gems.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
1
install-depends.sh
Executable file
1
install-depends.sh
Executable file
|
@ -0,0 +1 @@
|
|||
sudo apt install xorriso libc6-dev-i386
|
52
linker.ld
Normal file
52
linker.ld
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* The bootloader will look at this image and start execution at the symbol
|
||||
designated as the entry point. */
|
||||
ENTRY(_start)
|
||||
|
||||
/* Tell where the various sections of the object files will be put in the final
|
||||
kernel image. */
|
||||
SECTIONS
|
||||
{
|
||||
/* It used to be universally recommended to use 1M as a start offset,
|
||||
as it was effectively guaranteed to be available under BIOS systems.
|
||||
However, UEFI has made things more complicated, and experimental data
|
||||
strongly suggests that 2M is a safer place to load. In 2016, a new
|
||||
feature was introduced to the multiboot2 spec to inform bootloaders
|
||||
that a kernel can be loaded anywhere within a range of addresses and
|
||||
will be able to relocate itself to run from such a loader-selected
|
||||
address, in order to give the loader freedom in selecting a span of
|
||||
memory which is verified to be available by the firmware, in order to
|
||||
work around this issue. This does not use that feature, so 2M was
|
||||
chosen as a safer option than the traditional 1M. */
|
||||
. = 2M;
|
||||
|
||||
/* First put the multiboot header, as it is required to be put very early
|
||||
in the image or the bootloader won't recognize the file format.
|
||||
Next we'll put the .text section. */
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
/* Read-only data. */
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
/* Read-write data (initialized) */
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
/* Read-write data (uninitialized) and stack */
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
/* The compiler may produce other sections, by default it will put them in
|
||||
a segment with the same name. Simply add stuff here as needed. */
|
||||
}
|
5
quick-test.sh
Executable file
5
quick-test.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
if grub-file --is-x86-multiboot builds/iso/gems.elf; then
|
||||
echo multiboot confirmed
|
||||
else
|
||||
echo the file is not multiboot
|
||||
fi
|
1
source/THIRDPARTY/about
Normal file
1
source/THIRDPARTY/about
Normal file
|
@ -0,0 +1 @@
|
|||
This is the thirdparty material that made the kernel possible. The LICENSEs are in their respective folders, and as such these works are seperate.
|
133
source/THIRDPARTY/linux-old/CHANGES
Normal file
133
source/THIRDPARTY/linux-old/CHANGES
Normal file
|
@ -0,0 +1,133 @@
|
|||
CHANGES since 0.99 patchlevel 13:
|
||||
|
||||
- new kernel source layout: drivers separated
|
||||
- lots of networking bugs fixed, and new network card drivers (Alan Cox,
|
||||
Donald Becker &co)
|
||||
- sound driver added to the default source distribution (Hannu
|
||||
Savolainen)
|
||||
- updated SCSI driver code (Eric Youngdale, Drew Eckhardt &co)
|
||||
- readonly OS/2 filesystem support (HPFS) added (Chris Smith)
|
||||
- NTP support (Philip Gladstone, Torsten Duwe, ??)
|
||||
- fixed 16MB swap-area limit
|
||||
- lots of minor cleanups, buxfixes etc.
|
||||
|
||||
CHANGES since 0.99 patchlevel 12 and earlier:
|
||||
|
||||
- the bad memory management one-liner bug in pl12 is naturally fixed.
|
||||
- compiled with plain C by default instead of C++
|
||||
- ELF binary support (Eric Youngdale)
|
||||
- Quickport mouse support (and some changes to the PS/2 mouse driver)
|
||||
by Johan Myreen and co)
|
||||
- core file name change ("core" -> "core.xxxx" where xxxx is the name
|
||||
of the program that dumped code). Idea from ???. Also, core-files
|
||||
now correctly truncate any existing core file before being written.
|
||||
- some mmap() fixes: better error returns, and handling of non-fixed
|
||||
maps for /dev/mem etc.
|
||||
- one kludgy way to fix the wrong arp packets that have plagued net-2d
|
||||
(resulting in arp packets that had the first four bytes of the
|
||||
ethernet address as the IP address).
|
||||
- I fixed the mount-point handling of 'rename()' and 'unlink()/rmdir()'
|
||||
so that they should now work and/or give appropriate error messages.
|
||||
An early version of this patch was already sent to the KERNEL
|
||||
channel, which fixed the rename problem but not a similar bug with
|
||||
unlink.
|
||||
- packet mode fixes by Charles Hedrick. Sadly, these are likely to
|
||||
break old telnet/rlogin binaries, but it had to be done in order to
|
||||
communicate correctly with the rest of the world.
|
||||
- FPU emulator patches from Bill Metzenthen. The fprem1 insn should be
|
||||
correct now (not that anybody seems to have seen the incorrect
|
||||
behaviour..)
|
||||
- a few fixes for SCSI (Drew and Eric)
|
||||
- signal.c changes to handle multiple segments (for Wine) correctly.
|
||||
- updated drivers from Donald Becker: 3c509 and AT1500 drivers, but
|
||||
also some other drivers have been edited, and some networking fixes.
|
||||
|
||||
CHANGES since 0.99 patchlevel 11 and earlier:
|
||||
|
||||
- The memory manager cleanup has continued, and seems to be mostly
|
||||
ready, as proven by the ease of adding mmap() over NFS with the new
|
||||
routines. So yes, the pl12 kernel will demand-load your binaries
|
||||
over NFS, sharing code and clean data, as well as running shared
|
||||
libraries over NFS. Memory management by Eric and me, while the NFS
|
||||
mmap code was written by Jon Tombs,
|
||||
|
||||
- ** IMPORTANT **: The keyboard driver has been enhanced even further,
|
||||
and almost everything is completely re-mappable. This means that
|
||||
there is a new version of 'loadkeys' and 'dumpkeys' that you must use
|
||||
with this kernel or you'll have problems. The default keyboard is
|
||||
still the US mapping, but if you want to create your own mappings
|
||||
you'll have to load them with the new binaries. Get the 'kbd.tar.gz'
|
||||
archive from the same place you get the kernel.
|
||||
|
||||
The new keymappings allow things like function key string changes,
|
||||
remapping of the control keys, and freedom to remap any of the normal
|
||||
keyboard functions: including special features like rebooting,
|
||||
console switching etc. The keyboard remapping code has been done
|
||||
mostly by Risto Kankkunen (Risto.Kankkunen@Helsinki.FI).
|
||||
|
||||
- updated network drivers by Donald Becker
|
||||
|
||||
- updated serial drivers - tytso@Athena.mit.edu
|
||||
|
||||
- updated 387 emulation (Bill Metzenthen). The updated emulator code
|
||||
has more exact trigonometric functions and improved exception
|
||||
handling. It now behaves very much like a real 486, with only small
|
||||
changes (greater accuracy, slightly different denormal NaN handling
|
||||
etc - hard to detect the differences even if you are looking for
|
||||
them).
|
||||
|
||||
- network timer fixes by Florian La Roche (much cleaned up net/inet/timer.c
|
||||
and some bad race-conditions fixed).
|
||||
|
||||
- Scsi code updates by Eric Youngdale and others
|
||||
|
||||
- Sony CDU-31A CDROM driver by Corey Minyard added to the standard
|
||||
kernel distribution.
|
||||
|
||||
- The Mitsumi CDROM driver is now part of the standard kernel. Driver
|
||||
by Martin Harriss with patches by stud11@cc4.kuleuven.ac.be (yes, he
|
||||
probably has a real name, but no, I haven't found it) and Jon Tombs.
|
||||
|
||||
- various other minor patches (preliminary ldt support etc)
|
||||
|
||||
NOTABLE changes since patchlevel 10 or earlier:
|
||||
|
||||
- The memory manager has been cleaned up substantially, and mmap()
|
||||
works for MAP_PRIVATE. MAP_SHARED is still not supported for
|
||||
anything else than /dev/mem, but even so it actually is usable for a
|
||||
lot of applications. The shared library routines have been rewritten
|
||||
to use mmap() instead of the old hardcoded behaviour.
|
||||
|
||||
- The kernel is now compiled with C++ instead of plain C. Very few
|
||||
actual C++ features are used, but even so C++ allows for more
|
||||
type-checking and type-safe linkage.
|
||||
|
||||
- The filesystem routines have been cleaned up for multiple block
|
||||
sizes. None of the filesystems use it yet, but people are working on
|
||||
it.
|
||||
|
||||
- named pipes and normal pipes should hopefully have the right select()
|
||||
semantics in the presense/absense of writers.
|
||||
|
||||
- QIC-02 tape driver by Hennus Bergman
|
||||
|
||||
- selection patches in the default kernel
|
||||
|
||||
- fixed a bug in the pty code which led to busy waiting in some
|
||||
circumstances instead of sleeping.
|
||||
|
||||
- Compressed SLIP support (Charles Hedrick). See net/inet/CONFIG
|
||||
|
||||
- the 'clear_bit()' function was changed to return the previous setting
|
||||
of the bit instead of the old "error-code". This makes use of the
|
||||
bit operations more logical.
|
||||
|
||||
- udelay() function for short delays (busy-waiting) added. Used
|
||||
currently only by the QIC driver.
|
||||
|
||||
- fork() and sheduler changes to make task switches happen only from
|
||||
kernel mode to kernel mode. Cleaner and more portable than the old
|
||||
code which counted on being able to task-switch directly into user
|
||||
mode.
|
||||
|
||||
- debugging malloc code.
|
351
source/THIRDPARTY/linux-old/COPYING
Normal file
351
source/THIRDPARTY/linux-old/COPYING
Normal file
|
@ -0,0 +1,351 @@
|
|||
|
||||
NOTE! This copyright does *not* cover user programs that use kernel
|
||||
services by normal system calls - this is merely considered normal use
|
||||
of the kernel, and does *not* fall under the heading of "derived work".
|
||||
Also note that the GPL below is copyrighted by the Free Software
|
||||
Foundation, but the instance of code that it refers to (the linux
|
||||
kernel) is copyrighted by me and others who actually wrote it.
|
||||
|
||||
Linus Torvalds
|
||||
|
||||
----------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
242
source/THIRDPARTY/linux-old/Configure
Normal file
242
source/THIRDPARTY/linux-old/Configure
Normal file
|
@ -0,0 +1,242 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# This script is used to configure the linux kernel.
|
||||
#
|
||||
# It was inspired by the challenge in the original Configure script
|
||||
# to ``do something better'', combined with the actual need to ``do
|
||||
# something better'' because the old configure script wasn't flexible
|
||||
# enough.
|
||||
#
|
||||
# Please send comments / questions / bug fixes to raymondc@microsoft.com.
|
||||
#
|
||||
# Each line in the config file is a command.
|
||||
#
|
||||
# # internal comment
|
||||
#
|
||||
# Lines beginning with a `#' are ignored.
|
||||
#
|
||||
# : message
|
||||
#
|
||||
# `:' causes the line to be echoed to the screen.
|
||||
#
|
||||
# * external comment
|
||||
#
|
||||
# `*' causes the line to be placed in the output
|
||||
# configuration file as a comment as well as being
|
||||
# echoed to the screen.
|
||||
#
|
||||
# if condition
|
||||
# ... commands ...
|
||||
# else
|
||||
# ... commands ...
|
||||
# fi
|
||||
#
|
||||
# This does the obvious thing. The `else' clause is
|
||||
# optional. Conditionals can be nested.
|
||||
#
|
||||
# The `condition' can be any valid bash expression.
|
||||
# They typically involve tests against environment
|
||||
# variables set by configuration options. For example,
|
||||
#
|
||||
# if [ "$CONFIG_SCSI" = "y" ]
|
||||
# ...More stuff...
|
||||
# fi
|
||||
#
|
||||
# Note! That there is no `then' keyword.
|
||||
#
|
||||
# bool 'prompt' CONFIG_VARIABLE default
|
||||
#
|
||||
# This prompts the user for a boolean value.
|
||||
# The prompt may not contain an apostrophe.
|
||||
# `default' should be either `y' or `n'.
|
||||
# The user's response is recorded in four places.
|
||||
#
|
||||
# In .config, if `y'
|
||||
# CONFIG_VARIABLE = CONFIG_VARIABLE
|
||||
# In .config, if `n'
|
||||
# # CONFIG_VARIABLE is not set
|
||||
#
|
||||
# In autoconf.h, if `y'
|
||||
# #define CONFIG_VARIABLE 1
|
||||
# In autoconf.h, if `n'
|
||||
# #undef CONFIG_VARIABLE
|
||||
#
|
||||
# In config.in, if `y'
|
||||
# bool 'prompt' CONFIG_VARIABLE y
|
||||
# In config.in, if `n'
|
||||
# bool 'prompt' CONFIG_VARIABLE n
|
||||
#
|
||||
# In the environment of the Configure script, if `y'
|
||||
# CONFIG_VARIABLE = y
|
||||
# In the environment of the Configure script, if `n'
|
||||
# CONFIG_VARIABLE = n
|
||||
#
|
||||
# The value is placed into the environment of the Configure
|
||||
# script so that later parts of config.in can use the `if'
|
||||
# command to inspect the results of previous queries.
|
||||
#
|
||||
# int 'prompt' CONFIG_VARIABLE default
|
||||
#
|
||||
# This prompts the user for an integer value.
|
||||
# The prompt may not contain an apostrophe.
|
||||
# `default' should be an integer.
|
||||
#
|
||||
# The response is recorded as follows.
|
||||
#
|
||||
# In .config
|
||||
# CONFIG_VARIABLE = response
|
||||
# In autoconf.h
|
||||
# #define CONFIG_VARIABLE (response)
|
||||
# In config.in
|
||||
# int 'prompt' CONFIG_VARIABLE response
|
||||
# In the environment of the Configure script
|
||||
# CONFIG_VARIABLE = response
|
||||
#
|
||||
# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
|
||||
# with an empty IFS.
|
||||
|
||||
#
|
||||
# Make sure we're really running bash.
|
||||
#
|
||||
# I would really have preferred to write this script in a language with
|
||||
# better string handling, but alas, bash is the only scripting language
|
||||
# that I can be reasonable sure everybody has on their linux machine.
|
||||
#
|
||||
[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
|
||||
|
||||
# Disable filename globbing once and for all.
|
||||
# Enable function cacheing.
|
||||
set -f -h
|
||||
|
||||
#
|
||||
# readln reads a line into $ans.
|
||||
#
|
||||
# readln prompt default
|
||||
#
|
||||
function readln () {
|
||||
echo -n "$1"
|
||||
IFS='@' read ans </dev/tty || exit 1
|
||||
[ -z "$ans" ] && ans=$2
|
||||
}
|
||||
|
||||
# bool processes a boolean argument
|
||||
#
|
||||
# bool tail
|
||||
#
|
||||
function bool () {
|
||||
# Slimier hack to get bash to rescan a line.
|
||||
eval "set -- $1"
|
||||
ans=""
|
||||
while [ "$ans" != "y" -a "$ans" != "n" ]; do
|
||||
readln "$1 ($2) [$3] " "$3"
|
||||
done
|
||||
if [ "$ans" = "y" ]; then
|
||||
echo "$2 = $2" >>$CONFIG
|
||||
echo "#define $2 1" >>$CONFIG_H
|
||||
else
|
||||
echo "# $2 is not set" >>$CONFIG
|
||||
echo "#undef $2" >>$CONFIG_H
|
||||
fi
|
||||
raw_input_line="bool '$1' $2 $ans"
|
||||
eval "$2=$ans"
|
||||
}
|
||||
|
||||
# int processes an integer argument
|
||||
#
|
||||
# int tail
|
||||
#
|
||||
function int () {
|
||||
# Slimier hack to get bash to rescan a line.
|
||||
eval "set -- $1"
|
||||
ans="x"
|
||||
while [ $[$ans+0] != "$ans" ]; do
|
||||
readln "$1 ($2) [$3] " "$3"
|
||||
done
|
||||
echo "$2 = $ans" >>$CONFIG
|
||||
echo "#define $2 ($ans)" >>$CONFIG_H
|
||||
raw_input_line="int '$1' $2 $ans"
|
||||
eval "$2=$ans"
|
||||
}
|
||||
|
||||
CONFIG=.config~
|
||||
CONFIG_H=include/linux/autoconf.h
|
||||
|
||||
#
|
||||
# Make sure we start out with a clean slate.
|
||||
#
|
||||
> config.new
|
||||
echo "#" > $CONFIG
|
||||
echo "# Automatically generated make config: don't edit" >> $CONFIG
|
||||
echo "#" >> $CONFIG
|
||||
|
||||
echo "/*" > $CONFIG_H
|
||||
echo " * Automatically generated C config: don't edit" >> $CONFIG_H
|
||||
echo " */" >> $CONFIG_H
|
||||
|
||||
stack=''
|
||||
branch='t'
|
||||
|
||||
while IFS='@' read raw_input_line
|
||||
do
|
||||
# Slimy hack to get bash to rescan a line.
|
||||
read cmd rest <<-END_OF_COMMAND
|
||||
$raw_input_line
|
||||
END_OF_COMMAND
|
||||
|
||||
if [ "$cmd" = "*" ]; then
|
||||
if [ "$branch" = "t" ]; then
|
||||
echo "$raw_input_line"
|
||||
echo "# $rest" >>$CONFIG
|
||||
if [ "$prevcmd" != "*" ]; then
|
||||
echo >>$CONFIG_H
|
||||
echo "/* $rest" >>$CONFIG_H
|
||||
else
|
||||
echo " * $rest" >>$CONFIG_H
|
||||
fi
|
||||
prevcmd="*"
|
||||
fi
|
||||
else
|
||||
[ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H
|
||||
prevcmd=""
|
||||
case "$cmd" in
|
||||
:) [ "$branch" = "t" ] && echo "$raw_input_line" ;;
|
||||
int) [ "$branch" = "t" ] && int "$rest" ;;
|
||||
bool) [ "$branch" = "t" ] && bool "$rest" ;;
|
||||
exec) [ "$branch" = "t" ] && ( sh -c "$rest" ) ;;
|
||||
if) stack="$branch $stack"
|
||||
if [ "$branch" = "t" ] && eval "$rest"; then
|
||||
branch=t
|
||||
else
|
||||
branch=f
|
||||
fi ;;
|
||||
else) if [ "$branch" = "t" ]; then
|
||||
branch=f
|
||||
else
|
||||
read branch rest <<-END_OF_STACK
|
||||
$stack
|
||||
END_OF_STACK
|
||||
fi ;;
|
||||
fi) [ -z "$stack" ] && echo "Error! Extra fi." 1>&2
|
||||
read branch stack <<-END_OF_STACK
|
||||
$stack
|
||||
END_OF_STACK
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo "$raw_input_line" >>config.new
|
||||
done
|
||||
[ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H
|
||||
|
||||
[ -z "$stack" ] || echo "Error! Untermiated if." 1>&2
|
||||
|
||||
mv config.in config.old
|
||||
mv config.new config.in
|
||||
|
||||
echo
|
||||
echo "The linux kernel is now hopefully configured for your setup."
|
||||
echo "Check the top-level Makefile for additional configuration,"
|
||||
echo "and do a 'make dep ; make clean' if you want to be sure all"
|
||||
echo "the files are correctly re-made"
|
||||
echo
|
||||
|
||||
exit 0
|
296
source/THIRDPARTY/linux-old/Makefile
Normal file
296
source/THIRDPARTY/linux-old/Makefile
Normal file
|
@ -0,0 +1,296 @@
|
|||
VERSION = 0.99
|
||||
PATCHLEVEL = 15
|
||||
ALPHA =
|
||||
|
||||
all: Version zImage
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
|
||||
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
|
||||
else if [ -x /bin/bash ]; then echo /bin/bash; \
|
||||
else echo sh; fi ; fi)
|
||||
|
||||
#
|
||||
# Make "config" the default target if there is no configuration file or
|
||||
# "depend" the target if there is no top-level dependency information.
|
||||
#
|
||||
ifeq (.config,$(wildcard .config))
|
||||
include .config
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
include .depend
|
||||
else
|
||||
CONFIGURATION = depend
|
||||
endif
|
||||
else
|
||||
CONFIGURATION = config
|
||||
endif
|
||||
|
||||
ifdef CONFIGURATION
|
||||
CONFIGURE = dummy
|
||||
endif
|
||||
|
||||
#
|
||||
# ROOT_DEV specifies the default root-device when making the image.
|
||||
# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
|
||||
# the default of FLOPPY is used by 'build'.
|
||||
#
|
||||
|
||||
ROOT_DEV = CURRENT
|
||||
|
||||
#
|
||||
# If you want to preset the SVGA mode, uncomment the next line and
|
||||
# set SVGA_MODE to whatever number you want.
|
||||
# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
|
||||
# The number is the same as you would ordinarily press at bootup.
|
||||
#
|
||||
|
||||
SVGA_MODE= -DSVGA_MODE=NORMAL_VGA
|
||||
|
||||
#
|
||||
# standard CFLAGS
|
||||
#
|
||||
|
||||
CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe
|
||||
|
||||
ifdef CONFIG_CPP
|
||||
CFLAGS := $(CFLAGS) -x c++
|
||||
endif
|
||||
|
||||
ifdef CONFIG_M486
|
||||
CFLAGS := $(CFLAGS) -m486
|
||||
else
|
||||
CFLAGS := $(CFLAGS) -m386
|
||||
endif
|
||||
|
||||
#
|
||||
# if you want the ram-disk device, define this to be the
|
||||
# size in blocks.
|
||||
#
|
||||
|
||||
#RAMDISK = -DRAMDISK=512
|
||||
|
||||
AS86 =as86 -0 -a
|
||||
LD86 =ld86 -0
|
||||
|
||||
AS =as
|
||||
LD =ld
|
||||
HOSTCC =gcc
|
||||
CC =gcc -D__KERNEL__
|
||||
MAKE =make
|
||||
CPP =$(CC) -E
|
||||
AR =ar
|
||||
STRIP =strip
|
||||
|
||||
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o ipc/ipc.o
|
||||
FILESYSTEMS =fs/filesystems.a
|
||||
DRIVERS =drivers/block/block.a \
|
||||
drivers/char/char.a \
|
||||
drivers/net/net.a \
|
||||
ibcs/ibcs.o
|
||||
LIBS =lib/lib.a
|
||||
SUBDIRS =kernel drivers mm fs net ipc ibcs lib
|
||||
|
||||
KERNELHDRS =/usr/src/linux/include
|
||||
|
||||
ifdef CONFIG_SCSI
|
||||
DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SOUND
|
||||
DRIVERS := $(DRIVERS) drivers/sound/sound.a
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MATH_EMULATION
|
||||
DRIVERS := $(DRIVERS) drivers/FPU-emu/math.a
|
||||
endif
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) -S -o $*.s $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c -o $*.o $<
|
||||
|
||||
Version: dummy
|
||||
rm -f tools/version.h
|
||||
|
||||
config:
|
||||
$(CONFIG_SHELL) Configure $(OPTS) < config.in
|
||||
@if grep -s '^CONFIG_SOUND' .config~ ; then \
|
||||
$(MAKE) -C drivers/sound config; \
|
||||
else : ; fi
|
||||
mv .config~ .config
|
||||
|
||||
linuxsubdirs: dummy
|
||||
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
|
||||
|
||||
tools/./version.h: tools/version.h
|
||||
|
||||
tools/version.h: $(CONFIGURE) Makefile
|
||||
@./makever.sh
|
||||
@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL)$(ALPHA)\" > tools/version.h
|
||||
@echo \#define UTS_VERSION \"\#`cat .version` `date`\" >> tools/version.h
|
||||
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
|
||||
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
|
||||
@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
|
||||
@echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\" >> tools/version.h
|
||||
|
||||
tools/build: tools/build.c $(CONFIGURE)
|
||||
$(HOSTCC) $(CFLAGS) -o $@ $<
|
||||
|
||||
boot/head.o: $(CONFIGURE) boot/head.s
|
||||
|
||||
boot/head.s: boot/head.S $(CONFIGURE) include/linux/tasks.h
|
||||
$(CPP) -traditional $< -o $@
|
||||
|
||||
tools/version.o: tools/version.c tools/version.h
|
||||
|
||||
init/main.o: $(CONFIGURE) init/main.c
|
||||
$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
|
||||
|
||||
tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs
|
||||
$(LD) $(LDFLAGS) -T 1000 boot/head.o init/main.o tools/version.o \
|
||||
$(ARCHIVES) \
|
||||
$(FILESYSTEMS) \
|
||||
$(DRIVERS) \
|
||||
$(LIBS) \
|
||||
-o tools/system
|
||||
nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
|
||||
sort > System.map
|
||||
|
||||
boot/setup: boot/setup.o
|
||||
$(LD86) -s -o $@ $<
|
||||
|
||||
boot/setup.o: boot/setup.s
|
||||
$(AS86) -o $@ $<
|
||||
|
||||
boot/setup.s: boot/setup.S $(CONFIGURE) include/linux/config.h Makefile
|
||||
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
|
||||
|
||||
boot/bootsect: boot/bootsect.o
|
||||
$(LD86) -s -o $@ $<
|
||||
|
||||
boot/bootsect.o: boot/bootsect.s
|
||||
$(AS86) -o $@ $<
|
||||
|
||||
boot/bootsect.s: boot/bootsect.S $(CONFIGURE) include/linux/config.h Makefile
|
||||
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
|
||||
|
||||
zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
|
||||
$(MAKE) -C zBoot
|
||||
|
||||
zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build
|
||||
tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage
|
||||
sync
|
||||
|
||||
zdisk: zImage
|
||||
dd bs=8192 if=zImage of=/dev/fd0
|
||||
|
||||
zlilo: $(CONFIGURE) zImage
|
||||
if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi
|
||||
cat zImage > /vmlinuz
|
||||
if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
|
||||
|
||||
tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
|
||||
$(LD) $(LDFLAGS) -T 100000 boot/head.o init/main.o tools/version.o \
|
||||
$(ARCHIVES) \
|
||||
$(FILESYSTEMS) \
|
||||
$(DRIVERS) \
|
||||
$(LIBS) \
|
||||
-o tools/zSystem
|
||||
nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
|
||||
sort > zSystem.map
|
||||
|
||||
fs: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=fs
|
||||
|
||||
lib: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=lib
|
||||
|
||||
mm: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=mm
|
||||
|
||||
ipc: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=ipc
|
||||
|
||||
kernel: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=kernel
|
||||
|
||||
drivers: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=drivers
|
||||
|
||||
net: dummy
|
||||
$(MAKE) linuxsubdirs SUBDIRS=net
|
||||
|
||||
clean:
|
||||
rm -f kernel/ksyms.lst
|
||||
rm -f core `find . -name '*.[oas]' -print`
|
||||
rm -f core `find . -name 'core' -print`
|
||||
rm -f zImage zSystem.map tools/zSystem tools/system
|
||||
rm -f Image System.map boot/bootsect boot/setup
|
||||
rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback
|
||||
rm -f drivers/sound/configure
|
||||
rm -f init/*.o tools/build boot/*.o tools/*.o
|
||||
|
||||
mrproper: clean
|
||||
rm -f include/linux/autoconf.h tools/version.h
|
||||
rm -f drivers/sound/local.h
|
||||
rm -f .version .config* config.old
|
||||
rm -f .depend `find . -name .depend -print`
|
||||
|
||||
distclean: mrproper
|
||||
|
||||
backup: mrproper
|
||||
cd .. && tar cf - linux | gzip -9 > backup.gz
|
||||
sync
|
||||
|
||||
depend dep:
|
||||
touch tools/version.h
|
||||
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~
|
||||
for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~
|
||||
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
|
||||
rm -f tools/version.h
|
||||
mv .depend~ .depend
|
||||
|
||||
ifdef CONFIGURATION
|
||||
..$(CONFIGURATION):
|
||||
@echo
|
||||
@echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'"
|
||||
@echo
|
||||
$(MAKE) $(CONFIGURATION)
|
||||
@echo
|
||||
@echo "Successful. Try re-making (ignore the error that follows)"
|
||||
@echo
|
||||
exit 1
|
||||
|
||||
dummy: ..$(CONFIGURATION)
|
||||
|
||||
else
|
||||
|
||||
dummy:
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Leave these dummy entries for now to tell people that they are going away..
|
||||
#
|
||||
lilo:
|
||||
@echo
|
||||
@echo Uncompressed kernel images no longer supported. Use
|
||||
@echo \"make zlilo\" instead.
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
Image:
|
||||
@echo
|
||||
@echo Uncompressed kernel images no longer supported. Use
|
||||
@echo \"make zImage\" instead.
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
disk:
|
||||
@echo
|
||||
@echo Uncompressed kernel images no longer supported. Use
|
||||
@echo \"make zdisk\" instead.
|
||||
@echo
|
||||
@exit 1
|
181
source/THIRDPARTY/linux-old/README
Normal file
181
source/THIRDPARTY/linux-old/README
Normal file
|
@ -0,0 +1,181 @@
|
|||
|
||||
Linux kernel release 0.99 patchlevel 14
|
||||
|
||||
These are the release notes for linux version 0.99.14. Read them
|
||||
carefully, as they tell you what's new, explain how to install the
|
||||
kernel, and what to do if something goes wrong.
|
||||
|
||||
INSTALLING the kernel:
|
||||
|
||||
- if you install by patching, you need a *clean* 0.99.13 source tree,
|
||||
which presumably exists in /usr/src/linux. If so, to get the kernel
|
||||
patched, just do a
|
||||
|
||||
cd /usr/src
|
||||
patch -p0 < linux-0.99.patch14
|
||||
|
||||
and you should be ok. You may want to remove the backup files (xxx~
|
||||
or xxx.orig), and make sure that there are no failed patches (xxx# or
|
||||
xxx.rej).
|
||||
|
||||
- If you install the full sources, do a
|
||||
|
||||
cd /usr/src
|
||||
tar xvf linux-0.99.14.tar
|
||||
|
||||
to get it all put in place.
|
||||
|
||||
- make sure your /usr/include/linux and /usr/include/asm directories
|
||||
are just symlinks to the kernel sources:
|
||||
|
||||
cd /usr/include
|
||||
rm -rf linux
|
||||
rm -rf asm
|
||||
ln -s /usr/src/linux/include/linux .
|
||||
ln -s /usr/src/linux/include/asm .
|
||||
|
||||
- make sure you have no stale .o files and dependencies lying around:
|
||||
|
||||
cd /usr/src/linux
|
||||
make mrproper
|
||||
|
||||
You should now have the sources correctly installed.
|
||||
|
||||
CONFIGURING the kernel:
|
||||
|
||||
- do a "make config" to configure the basic kernel. "make config"
|
||||
needs bash to work: it will search for bash in $BASH, /bin/bash and
|
||||
/bin/sh (in that order), so hopefully one of those is correct.
|
||||
|
||||
NOTES on "make config":
|
||||
- compiling the kernel with "-m486" for a number of 486-specific
|
||||
will result in a kernel that still works on a 386: it may be
|
||||
slightly larger and possibly slower by an insignificant amount,
|
||||
but it should not hurt performance.
|
||||
- A kernel with math-emulation compiled in will still use the
|
||||
coprocessor if one is present: the math emulation will just
|
||||
never get used in that case. The kernel will be slighly larger,
|
||||
but will work on different machines regardless of whether they
|
||||
have a math coprocessor or not.
|
||||
- the "kernel hacking" configuration details usually result in a
|
||||
bigger or slower kernel (or both), and can even make the kernel
|
||||
less stable by configuring some routines to actively try to
|
||||
break bad code to find kernel problems (kmalloc()). Thus you
|
||||
should probably answer 'n' to the questions for a "production"
|
||||
kernel.
|
||||
|
||||
- edit drivers/net/CONFIG to configure the networking parts of the
|
||||
kernel. The comments should hopefully clarify it all.
|
||||
|
||||
- Check the top Makefile for further site-dependent configuration
|
||||
(default SVGA mode etc).
|
||||
|
||||
- Finally, do a "make dep" to set up all the dependencies correctly.
|
||||
|
||||
COMPILING the kernel:
|
||||
|
||||
- make sure you have gcc-2.4.5 or newer available with g++. It seems
|
||||
older gcc versions can have problems compiling linux 0.99.10 and
|
||||
newer versions. If you upgrade, remember to get the new binutils
|
||||
package too (for as/ld/nm and company)
|
||||
|
||||
- do a "make zImage" to create a compressed kernel image. If you want
|
||||
to make a bootdisk (without root filesystem or lilo), insert a floppy
|
||||
in your A: drive, and do a "make zdisk". It is also possible to do
|
||||
"make zlilo" if you have lilo installed to suit the kernel makefiles,
|
||||
but you may want to check your particular lilo setup first.
|
||||
|
||||
- keep a backup kernel handy in case something goes wrong.
|
||||
|
||||
- In order to boot your new kernel, you'll need to copy the kernel
|
||||
image (found in /usr/src/linux/zImage after compilation) to the place
|
||||
where your regular bootable kernel is found.
|
||||
|
||||
For some, this is on a floppy disk, in which case you can "cp
|
||||
/usr/src/linux/zImage /dev/fd0" to make a bootable floppy.
|
||||
|
||||
If you boot Linux from the hard drive, chances are you use LILO uses
|
||||
the kernel image as specified in the file /etc/lilo/config. The
|
||||
kernel image file is usually /vmlinux, or /Image, or /etc/Image. To
|
||||
use the new kernel, copy the new image over the old one (save a
|
||||
backup of the original!). Then, you MUST REINSTALL LILO!! If you
|
||||
don't, you won't be able to boot the new kernel image.
|
||||
|
||||
Reinstalling LILO is usually a matter of running /etc/lilo/install.
|
||||
You may wish to edit /etc/lilo/config to specify an entry for your
|
||||
old kernel image (say, /vmlinux.old) in case the new one does not
|
||||
work. See the LILO docs for more information.
|
||||
|
||||
After reinstalling LILO, you should be all set. Shutdown the system,
|
||||
reboot, and enjoy!
|
||||
|
||||
If you ever need to change the default root device, video mode,
|
||||
ramdisk size, etc. in the kernel image, use the 'rdev' program (or
|
||||
alternatively the LILO boot options when appropriate). No need to
|
||||
recompile the kernel to change these parameters.
|
||||
|
||||
- reboot with the new kernel and enjoy.
|
||||
|
||||
IF SOMETHING GOES WRONG:
|
||||
|
||||
- if you have problems that seem to be due to kernel bugs, please mail
|
||||
them to me (Linus.Torvalds@Helsinki.FI), and possibly to any other
|
||||
relevant mailing-list or to the newsgroup. The mailing-lists are
|
||||
useful especially for SCSI and NETworking problems, as I can't test
|
||||
either of those personally anyway.
|
||||
|
||||
- In all bug-reports, *please* tell what kernel you are talking about,
|
||||
how to duplicate the problem, and what your setup is (use your common
|
||||
sense). If the problem is new, tell me so, and if the problem is
|
||||
old, please try to tell me when you first noticed it.
|
||||
|
||||
- if the bug results in a message like
|
||||
|
||||
unable to handle kernel paging request at address C0000010
|
||||
Oops: 0002
|
||||
EIP: 0010:xxxxxxxx
|
||||
eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
|
||||
esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
|
||||
ds: xxxx es: xxxx fs: xxxx gs: xxxx
|
||||
Pid: xx, process nr: xx
|
||||
xx xx xx xx xx xx xx xx xx xx
|
||||
|
||||
or similar kernel debugging information on your screen or in your
|
||||
system log, please duplicate it *exactly*. The dump may look
|
||||
incomprehensible to you, but it does contain information that may
|
||||
help debugging the problem. The text above the dump is also
|
||||
important: it tells something about why the kernel dumped code (in
|
||||
the above example it's due to a bad kernel pointer)
|
||||
|
||||
- in debugging dumps like the above, it helps enourmously if you can
|
||||
look up what the EIP value means. The hex value as such doesn't help
|
||||
me or anybody else very much: it will depend on your particular
|
||||
kernel setup. What you should do is take the hex value from the EIP
|
||||
line (ignore the "0010:"), and look it up in the kernel namelist to
|
||||
see which kernel function contains the offending address.
|
||||
|
||||
To find out the kernel function name, you'll need to find the system
|
||||
binary associated with the kernel that exhibited the symptom. In the
|
||||
case of compressed kernels, this will be 'linux/tools/zSystem', while
|
||||
uncompressed kernels use the file 'tools/system'. To extract the
|
||||
namelist and match it against the EIP from the kernel crash, do:
|
||||
|
||||
nm tools/zSystem | sort | less
|
||||
|
||||
This will give you a list of kernel addresses sorted in ascending
|
||||
order, from which it is simple to find the function that contains the
|
||||
offending address. Note that the address given by the kernel
|
||||
debugging messages will not necessarily match exactly with the
|
||||
function addresses (in fact, that is very unlikely), so you can't
|
||||
just 'grep' the list: the list will, however, give you the starting
|
||||
point of each kernel function, so by looking for the function that
|
||||
has a starting address lower than the one you are searching for but
|
||||
is followed by a function with a higher address you will find the one
|
||||
you want. In fact, it may be a good idea to include a bit of
|
||||
"context" in your problem report, giving a few lines around the
|
||||
interesting one.
|
||||
|
||||
If you for some reason cannot do the above (you have a pre-compiled
|
||||
kernel image or similar), telling me as much about your setup as
|
||||
possible will help.
|
||||
|
450
source/THIRDPARTY/linux-old/boot/bootsect.S
Normal file
450
source/THIRDPARTY/linux-old/boot/bootsect.S
Normal file
|
@ -0,0 +1,450 @@
|
|||
!
|
||||
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
|
||||
! 0x7F00 is 0x7F000 bytes = 508kB, more than enough for current
|
||||
! versions of linux which compress the kernel
|
||||
!
|
||||
#include <linux/config.h>
|
||||
SYSSIZE = DEF_SYSSIZE
|
||||
!
|
||||
! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
|
||||
! modified by Drew Eckhardt
|
||||
! modified by Bruce Evans (bde)
|
||||
!
|
||||
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
|
||||
! itself out of the way to address 0x90000, and jumps there.
|
||||
!
|
||||
! bde - should not jump blindly, there may be systems with only 512K low
|
||||
! memory. Use int 0x12 to get the top of memory, etc.
|
||||
!
|
||||
! It then loads 'setup' directly after itself (0x90200), and the system
|
||||
! at 0x10000, using BIOS interrupts.
|
||||
!
|
||||
! NOTE! currently system is at most (8*65536-4096) bytes long. This should
|
||||
! be no problem, even in the future. I want to keep it simple. This 508 kB
|
||||
! kernel size should be enough, especially as this doesn't contain the
|
||||
! buffer cache as in minix (and especially now that the kernel is
|
||||
! compressed :-)
|
||||
!
|
||||
! The loader has been made as simple as possible, and continuos
|
||||
! read errors will result in a unbreakable loop. Reboot by hand. It
|
||||
! loads pretty fast by getting whole tracks at a time whenever possible.
|
||||
|
||||
.text
|
||||
|
||||
SETUPSECS = 4 ! nr of setup-sectors
|
||||
BOOTSEG = 0x07C0 ! original address of boot-sector
|
||||
INITSEG = DEF_INITSEG ! we move boot here - out of the way
|
||||
SETUPSEG = DEF_SETUPSEG ! setup starts here
|
||||
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
|
||||
|
||||
! ROOT_DEV & SWAP_DEV are now written by "build".
|
||||
ROOT_DEV = 0
|
||||
SWAP_DEV = 0
|
||||
#ifndef SVGA_MODE
|
||||
#define SVGA_MODE ASK_VGA
|
||||
#endif
|
||||
#ifndef RAMDISK
|
||||
#define RAMDISK 0
|
||||
#endif
|
||||
#ifndef CONFIG_ROOT_RDONLY
|
||||
#define CONFIG_ROOT_RDONLY 0
|
||||
#endif
|
||||
|
||||
! ld86 requires an entry symbol. This may as well be the usual one.
|
||||
.globl _main
|
||||
_main:
|
||||
#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
|
||||
int 3
|
||||
#endif
|
||||
mov ax,#BOOTSEG
|
||||
mov ds,ax
|
||||
mov ax,#INITSEG
|
||||
mov es,ax
|
||||
mov cx,#256
|
||||
sub si,si
|
||||
sub di,di
|
||||
cld
|
||||
rep
|
||||
movsw
|
||||
jmpi go,INITSEG
|
||||
|
||||
go: mov ax,cs
|
||||
mov dx,#0x4000-12 ! 0x4000 is arbitrary value >= length of
|
||||
! bootsect + length of setup + room for stack
|
||||
! 12 is disk parm size
|
||||
|
||||
! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
|
||||
! wouldn't have to worry about this if we checked the top of memory. Also
|
||||
! my BIOS can be configured to put the wini drive tables in high memory
|
||||
! instead of in the vector table. The old stack might have clobbered the
|
||||
! drive table.
|
||||
|
||||
mov ds,ax
|
||||
mov es,ax
|
||||
mov ss,ax ! put stack at INITSEG:0x4000-12.
|
||||
mov sp,dx
|
||||
/*
|
||||
* Many BIOS's default disk parameter tables will not
|
||||
* recognize multi-sector reads beyond the maximum sector number
|
||||
* specified in the default diskette parameter tables - this may
|
||||
* mean 7 sectors in some cases.
|
||||
*
|
||||
* Since single sector reads are slow and out of the question,
|
||||
* we must take care of this by creating new parameter tables
|
||||
* (for the first disk) in RAM. We will set the maximum sector
|
||||
* count to 18 - the most we will encounter on an HD 1.44.
|
||||
*
|
||||
* High doesn't hurt. Low does.
|
||||
*
|
||||
* Segments are as follows: ds=es=ss=cs - INITSEG,
|
||||
* fs = 0, gs = parameter table segment
|
||||
*/
|
||||
|
||||
push #0
|
||||
pop fs
|
||||
mov bx,#0x78 ! fs:bx is parameter table address
|
||||
seg fs
|
||||
lgs si,(bx) ! gs:si is source
|
||||
|
||||
mov di,dx ! es:di is destination
|
||||
mov cx,#6 ! copy 12 bytes
|
||||
cld
|
||||
|
||||
rep
|
||||
seg gs
|
||||
movsw
|
||||
|
||||
mov di,dx
|
||||
movb 4(di),*18 ! patch sector count
|
||||
|
||||
seg fs
|
||||
mov (bx),di
|
||||
seg fs
|
||||
mov 2(bx),es
|
||||
|
||||
mov ax,cs
|
||||
mov fs,ax
|
||||
mov gs,ax
|
||||
|
||||
xor ah,ah ! reset FDC
|
||||
xor dl,dl
|
||||
int 0x13
|
||||
|
||||
! load the setup-sectors directly after the bootblock.
|
||||
! Note that 'es' is already set up.
|
||||
|
||||
load_setup:
|
||||
xor dx, dx ! drive 0, head 0
|
||||
mov cx,#0x0002 ! sector 2, track 0
|
||||
mov bx,#0x0200 ! address = 512, in INITSEG
|
||||
mov ax,#0x0200+SETUPSECS ! service 2, nr of sectors
|
||||
! (assume all on head 0, track 0)
|
||||
int 0x13 ! read it
|
||||
jnc ok_load_setup ! ok - continue
|
||||
|
||||
push ax ! dump error code
|
||||
call print_nl
|
||||
mov bp, sp
|
||||
call print_hex
|
||||
pop ax
|
||||
|
||||
xor dl, dl ! reset FDC
|
||||
xor ah, ah
|
||||
int 0x13
|
||||
jmp load_setup
|
||||
|
||||
ok_load_setup:
|
||||
|
||||
! Get disk drive parameters, specifically nr of sectors/track
|
||||
|
||||
#if 0
|
||||
|
||||
! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
|
||||
! disks. It doesn't work for one of my BIOS's (1987 Award). It was
|
||||
! fatal not to check the error code.
|
||||
|
||||
xor dl,dl
|
||||
mov ah,#0x08 ! AH=8 is get drive parameters
|
||||
int 0x13
|
||||
xor ch,ch
|
||||
#else
|
||||
|
||||
! It seems that there is no BIOS call to get the number of sectors. Guess
|
||||
! 18 sectors if sector 18 can be read, 15 if sector 15 can be read.
|
||||
! Otherwise guess 9.
|
||||
|
||||
xor dx, dx ! drive 0, head 0
|
||||
mov cx,#0x0012 ! sector 18, track 0
|
||||
mov bx,#0x0200+SETUPSECS*0x200 ! address after setup (es = cs)
|
||||
mov ax,#0x0201 ! service 2, 1 sector
|
||||
int 0x13
|
||||
jnc got_sectors
|
||||
mov cl,#0x0f ! sector 15
|
||||
mov ax,#0x0201 ! service 2, 1 sector
|
||||
int 0x13
|
||||
jnc got_sectors
|
||||
mov cl,#0x09
|
||||
|
||||
#endif
|
||||
|
||||
got_sectors:
|
||||
seg cs
|
||||
mov sectors,cx
|
||||
mov ax,#INITSEG
|
||||
mov es,ax
|
||||
|
||||
! Print some inane message
|
||||
|
||||
mov ah,#0x03 ! read cursor pos
|
||||
xor bh,bh
|
||||
int 0x10
|
||||
|
||||
mov cx,#9
|
||||
mov bx,#0x0007 ! page 0, attribute 7 (normal)
|
||||
mov bp,#msg1
|
||||
mov ax,#0x1301 ! write string, move cursor
|
||||
int 0x10
|
||||
|
||||
! ok, we've written the message, now
|
||||
! we want to load the system (at 0x10000)
|
||||
|
||||
mov ax,#SYSSEG
|
||||
mov es,ax ! segment of 0x010000
|
||||
call read_it
|
||||
call kill_motor
|
||||
call print_nl
|
||||
|
||||
! After that we check which root-device to use. If the device is
|
||||
! defined (!= 0), nothing is done and the given device is used.
|
||||
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
|
||||
! on the number of sectors that the BIOS reports currently.
|
||||
|
||||
seg cs
|
||||
mov ax,root_dev
|
||||
or ax,ax
|
||||
jne root_defined
|
||||
seg cs
|
||||
mov bx,sectors
|
||||
mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
|
||||
cmp bx,#15
|
||||
je root_defined
|
||||
mov ax,#0x021c ! /dev/PS0 - 1.44Mb
|
||||
cmp bx,#18
|
||||
je root_defined
|
||||
mov ax,#0x0200 ! /dev/fd0 - autodetect
|
||||
root_defined:
|
||||
seg cs
|
||||
mov root_dev,ax
|
||||
|
||||
! after that (everyting loaded), we jump to
|
||||
! the setup-routine loaded directly after
|
||||
! the bootblock:
|
||||
|
||||
jmpi 0,SETUPSEG
|
||||
|
||||
! This routine loads the system at address 0x10000, making sure
|
||||
! no 64kB boundaries are crossed. We try to load it as fast as
|
||||
! possible, loading whole tracks whenever we can.
|
||||
!
|
||||
! in: es - starting address segment (normally 0x1000)
|
||||
!
|
||||
sread: .word 1+SETUPSECS ! sectors read of current track
|
||||
head: .word 0 ! current head
|
||||
track: .word 0 ! current track
|
||||
|
||||
read_it:
|
||||
mov ax,es
|
||||
test ax,#0x0fff
|
||||
die: jne die ! es must be at 64kB boundary
|
||||
xor bx,bx ! bx is starting address within segment
|
||||
rp_read:
|
||||
mov ax,es
|
||||
sub ax,#SYSSEG
|
||||
cmp ax,syssize ! have we loaded all yet?
|
||||
jbe ok1_read
|
||||
ret
|
||||
ok1_read:
|
||||
seg cs
|
||||
mov ax,sectors
|
||||
sub ax,sread
|
||||
mov cx,ax
|
||||
shl cx,#9
|
||||
add cx,bx
|
||||
jnc ok2_read
|
||||
je ok2_read
|
||||
xor ax,ax
|
||||
sub ax,bx
|
||||
shr ax,#9
|
||||
ok2_read:
|
||||
call read_track
|
||||
mov cx,ax
|
||||
add ax,sread
|
||||
seg cs
|
||||
cmp ax,sectors
|
||||
jne ok3_read
|
||||
mov ax,#1
|
||||
sub ax,head
|
||||
jne ok4_read
|
||||
inc track
|
||||
ok4_read:
|
||||
mov head,ax
|
||||
xor ax,ax
|
||||
ok3_read:
|
||||
mov sread,ax
|
||||
shl cx,#9
|
||||
add bx,cx
|
||||
jnc rp_read
|
||||
mov ax,es
|
||||
add ah,#0x10
|
||||
mov es,ax
|
||||
xor bx,bx
|
||||
jmp rp_read
|
||||
|
||||
read_track:
|
||||
pusha
|
||||
pusha
|
||||
mov ax, #0xe2e ! loading... message 2e = .
|
||||
mov bx, #7
|
||||
int 0x10
|
||||
popa
|
||||
|
||||
mov dx,track
|
||||
mov cx,sread
|
||||
inc cx
|
||||
mov ch,dl
|
||||
mov dx,head
|
||||
mov dh,dl
|
||||
and dx,#0x0100
|
||||
mov ah,#2
|
||||
|
||||
push dx ! save for error dump
|
||||
push cx
|
||||
push bx
|
||||
push ax
|
||||
|
||||
int 0x13
|
||||
jc bad_rt
|
||||
add sp, #8
|
||||
popa
|
||||
ret
|
||||
|
||||
bad_rt: push ax ! save error code
|
||||
call print_all ! ah = error, al = read
|
||||
|
||||
|
||||
xor ah,ah
|
||||
xor dl,dl
|
||||
int 0x13
|
||||
|
||||
|
||||
add sp, #10
|
||||
popa
|
||||
jmp read_track
|
||||
|
||||
/*
|
||||
* print_all is for debugging purposes.
|
||||
* It will print out all of the registers. The assumption is that this is
|
||||
* called from a routine, with a stack frame like
|
||||
* dx
|
||||
* cx
|
||||
* bx
|
||||
* ax
|
||||
* error
|
||||
* ret <- sp
|
||||
*
|
||||
*/
|
||||
|
||||
print_all:
|
||||
mov cx, #5 ! error code + 4 registers
|
||||
mov bp, sp
|
||||
|
||||
print_loop:
|
||||
push cx ! save count left
|
||||
call print_nl ! nl for readability
|
||||
|
||||
cmp cl, 5
|
||||
jae no_reg ! see if register name is needed
|
||||
|
||||
mov ax, #0xe05 + 'A - 1
|
||||
sub al, cl
|
||||
int 0x10
|
||||
|
||||
mov al, #'X
|
||||
int 0x10
|
||||
|
||||
mov al, #':
|
||||
int 0x10
|
||||
|
||||
no_reg:
|
||||
add bp, #2 ! next register
|
||||
call print_hex ! print it
|
||||
pop cx
|
||||
loop print_loop
|
||||
ret
|
||||
|
||||
print_nl:
|
||||
mov ax, #0xe0d ! CR
|
||||
int 0x10
|
||||
mov al, #0xa ! LF
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
/*
|
||||
* print_hex is for debugging purposes, and prints the word
|
||||
* pointed to by ss:bp in hexadecmial.
|
||||
*/
|
||||
|
||||
print_hex:
|
||||
mov cx, #4 ! 4 hex digits
|
||||
mov dx, (bp) ! load word into dx
|
||||
print_digit:
|
||||
rol dx, #4 ! rotate so that lowest 4 bits are used
|
||||
mov ah, #0xe
|
||||
mov al, dl ! mask off so we have only next nibble
|
||||
and al, #0xf
|
||||
add al, #'0 ! convert to 0-based digit
|
||||
cmp al, #'9 ! check for overflow
|
||||
jbe good_digit
|
||||
add al, #'A - '0 - 10
|
||||
|
||||
good_digit:
|
||||
int 0x10
|
||||
loop print_digit
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* This procedure turns off the floppy drive motor, so
|
||||
* that we enter the kernel in a known state, and
|
||||
* don't have to worry about it later.
|
||||
*/
|
||||
kill_motor:
|
||||
push dx
|
||||
mov dx,#0x3f2
|
||||
xor al, al
|
||||
outb
|
||||
pop dx
|
||||
ret
|
||||
|
||||
sectors:
|
||||
.word 0
|
||||
|
||||
msg1:
|
||||
.byte 13,10
|
||||
.ascii "Loading"
|
||||
|
||||
.org 498
|
||||
root_flags:
|
||||
.word CONFIG_ROOT_RDONLY
|
||||
syssize:
|
||||
.word SYSSIZE
|
||||
swap_dev:
|
||||
.word SWAP_DEV
|
||||
ram_size:
|
||||
.word RAMDISK
|
||||
vid_mode:
|
||||
.word SVGA_MODE
|
||||
root_dev:
|
||||
.word ROOT_DEV
|
||||
boot_flag:
|
||||
.word 0xAA55
|
354
source/THIRDPARTY/linux-old/boot/head.S
Normal file
354
source/THIRDPARTY/linux-old/boot/head.S
Normal file
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* linux/boot/head.S
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* head.S contains the 32-bit startup code.
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl _idt,_gdt,
|
||||
.globl _swapper_pg_dir,_pg0
|
||||
.globl _empty_bad_page
|
||||
.globl _empty_bad_page_table
|
||||
.globl _empty_zero_page
|
||||
.globl _tmp_floppy_area,_floppy_track_buffer
|
||||
|
||||
#include <linux/tasks.h>
|
||||
#include <linux/segment.h>
|
||||
|
||||
#define CL_MAGIC_ADDR 0x90020
|
||||
#define CL_MAGIC 0xA33F
|
||||
#define CL_BASE_ADDR 0x90000
|
||||
#define CL_OFFSET 0x90022
|
||||
|
||||
/*
|
||||
* swapper_pg_dir is the main page directory, address 0x00001000 (or at
|
||||
* address 0x00101000 for a compressed boot).
|
||||
*/
|
||||
startup_32:
|
||||
cld
|
||||
movl $(KERNEL_DS),%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
mov %ax,%fs
|
||||
mov %ax,%gs
|
||||
lss _stack_start,%esp
|
||||
/*
|
||||
* Clear BSS first so that there are no surprises...
|
||||
*/
|
||||
xorl %eax,%eax
|
||||
movl $__edata,%edi
|
||||
movl $__end,%ecx
|
||||
subl %edi,%ecx
|
||||
cld
|
||||
rep
|
||||
stosb
|
||||
/*
|
||||
* start system 32-bit setup. We need to re-do some of the things done
|
||||
* in 16-bit mode for the "real" operations.
|
||||
*/
|
||||
call setup_idt
|
||||
xorl %eax,%eax
|
||||
1: incl %eax # check that A20 really IS enabled
|
||||
movl %eax,0x000000 # loop forever if it isn't
|
||||
cmpl %eax,0x100000
|
||||
je 1b
|
||||
/*
|
||||
* Initialize eflags. Some BIOS's leave bits like NT set. This would
|
||||
* confuse the debugger if this code is traced.
|
||||
* XXX - best to initialize before switching to protected mode.
|
||||
*/
|
||||
pushl $0
|
||||
popfl
|
||||
/*
|
||||
* Copy bootup parameters out of the way. First 2kB of
|
||||
* _empty_zero_page is for boot parameters, second 2kB
|
||||
* is for the command line.
|
||||
*/
|
||||
movl $0x90000,%esi
|
||||
movl $_empty_zero_page,%edi
|
||||
movl $512,%ecx
|
||||
cld
|
||||
rep
|
||||
movsl
|
||||
xorl %eax,%eax
|
||||
movl $512,%ecx
|
||||
rep
|
||||
stosl
|
||||
cmpw $(CL_MAGIC),CL_MAGIC_ADDR
|
||||
jne 1f
|
||||
movl $_empty_zero_page+2048,%edi
|
||||
movzwl CL_OFFSET,%esi
|
||||
addl $(CL_BASE_ADDR),%esi
|
||||
movl $2048,%ecx
|
||||
rep
|
||||
movsb
|
||||
1:
|
||||
/* check if it is 486 or 386. */
|
||||
/*
|
||||
* XXX - this does a lot of unnecessary setup. Alignment checks don't
|
||||
* apply at our cpl of 0 and the stack ought to be aligned already, and
|
||||
* we don't need to preserve eflags.
|
||||
*/
|
||||
movl %esp,%edi # save stack pointer
|
||||
andl $0xfffffffc,%esp # align stack to avoid AC fault
|
||||
movl $3,_x86
|
||||
pushfl # push EFLAGS
|
||||
popl %eax # get EFLAGS
|
||||
movl %eax,%ecx # save original EFLAGS
|
||||
xorl $0x40000,%eax # flip AC bit in EFLAGS
|
||||
pushl %eax # copy to EFLAGS
|
||||
popfl # set EFLAGS
|
||||
pushfl # get new EFLAGS
|
||||
popl %eax # put it in eax
|
||||
xorl %ecx,%eax # change in flags
|
||||
andl $0x40000,%eax # check if AC bit changed
|
||||
je is386
|
||||
movl $4,_x86
|
||||
movl %ecx,%eax
|
||||
xorl $0x200000,%eax # check ID flag
|
||||
pushl %eax
|
||||
popfl # if we are on a straight 486DX, SX, or
|
||||
pushfl # 487SX we can't change it
|
||||
popl %eax
|
||||
xorl %ecx,%eax
|
||||
andl $0x200000,%eax
|
||||
je is486
|
||||
isnew: pushl %ecx # restore original EFLAGS
|
||||
popfl
|
||||
movl $1, %eax # Use the CPUID instruction to
|
||||
.byte 0x0f, 0xa2 # check the processor type
|
||||
andl $0xf00, %eax # Set _x86 with the family
|
||||
shrl $8, %eax # returned.
|
||||
movl %eax, _x86
|
||||
movl %edi,%esp # restore esp
|
||||
movl %cr0,%eax # 486+
|
||||
andl $0x80000011,%eax # Save PG,PE,ET
|
||||
orl $0x50022,%eax # set AM, WP, NE and MP
|
||||
jmp 2f
|
||||
is486: pushl %ecx # restore original EFLAGS
|
||||
popfl
|
||||
movl %edi,%esp # restore esp
|
||||
movl %cr0,%eax # 486
|
||||
andl $0x80000011,%eax # Save PG,PE,ET
|
||||
orl $0x50022,%eax # set AM, WP, NE and MP
|
||||
jmp 2f
|
||||
is386: pushl %ecx # restore original EFLAGS
|
||||
popfl
|
||||
movl %edi,%esp # restore esp
|
||||
movl %cr0,%eax # 386
|
||||
andl $0x80000011,%eax # Save PG,PE,ET
|
||||
orl $2,%eax # set MP
|
||||
2: movl %eax,%cr0
|
||||
call check_x87
|
||||
call setup_paging
|
||||
lgdt gdt_descr
|
||||
lidt idt_descr
|
||||
ljmp $(KERNEL_CS),$1f
|
||||
1: movl $(KERNEL_DS),%eax # reload all the segment registers
|
||||
mov %ax,%ds # after changing gdt.
|
||||
mov %ax,%es
|
||||
mov %ax,%fs
|
||||
mov %ax,%gs
|
||||
lss _stack_start,%esp
|
||||
xorl %eax,%eax
|
||||
lldt %ax
|
||||
pushl %eax # These are the parameters to main :-)
|
||||
pushl %eax
|
||||
pushl %eax
|
||||
cld # gcc2 wants the direction flag cleared at all times
|
||||
call _start_kernel
|
||||
L6:
|
||||
jmp L6 # main should never return here, but
|
||||
# just in case, we know what happens.
|
||||
|
||||
/*
|
||||
* We depend on ET to be correct. This checks for 287/387.
|
||||
*/
|
||||
check_x87:
|
||||
movl $0,_hard_math
|
||||
clts
|
||||
fninit
|
||||
fstsw %ax
|
||||
cmpb $0,%al
|
||||
je 1f
|
||||
movl %cr0,%eax /* no coprocessor: have to set bits */
|
||||
xorl $4,%eax /* set EM */
|
||||
movl %eax,%cr0
|
||||
ret
|
||||
.align 2
|
||||
1: movl $1,_hard_math
|
||||
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
|
||||
ret
|
||||
|
||||
/*
|
||||
* setup_idt
|
||||
*
|
||||
* sets up a idt with 256 entries pointing to
|
||||
* ignore_int, interrupt gates. It doesn't actually load
|
||||
* idt - that can be done only after paging has been enabled
|
||||
* and the kernel moved to 0xC0000000. Interrupts
|
||||
* are enabled elsewhere, when we can be relatively
|
||||
* sure everything is ok.
|
||||
*/
|
||||
setup_idt:
|
||||
lea ignore_int,%edx
|
||||
movl $(KERNEL_CS << 16),%eax
|
||||
movw %dx,%ax /* selector = 0x0010 = cs */
|
||||
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
|
||||
|
||||
lea _idt,%edi
|
||||
mov $256,%ecx
|
||||
rp_sidt:
|
||||
movl %eax,(%edi)
|
||||
movl %edx,4(%edi)
|
||||
addl $8,%edi
|
||||
dec %ecx
|
||||
jne rp_sidt
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* Setup_paging
|
||||
*
|
||||
* This routine sets up paging by setting the page bit
|
||||
* in cr0. The page tables are set up, identity-mapping
|
||||
* the first 4MB. The rest are initialized later.
|
||||
*
|
||||
* (ref: added support for up to 32mb, 17Apr92) -- Rik Faith
|
||||
* (ref: update, 25Sept92) -- croutons@crunchy.uucp
|
||||
* (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
|
||||
*/
|
||||
.align 2
|
||||
setup_paging:
|
||||
movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */
|
||||
xorl %eax,%eax
|
||||
movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
|
||||
cld;rep;stosl
|
||||
/* Identity-map the kernel in low 4MB memory for ease of transition */
|
||||
movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
|
||||
/* But the real place is at 0xC0000000 */
|
||||
movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
|
||||
movl $_pg0+4092,%edi
|
||||
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
|
||||
std
|
||||
1: stosl /* fill the page backwards - more efficient :-) */
|
||||
subl $0x1000,%eax
|
||||
jge 1b
|
||||
cld
|
||||
movl $_swapper_pg_dir,%eax
|
||||
movl %eax,%cr3 /* cr3 - page directory start */
|
||||
movl %cr0,%eax
|
||||
orl $0x80000000,%eax
|
||||
movl %eax,%cr0 /* set paging (PG) bit */
|
||||
ret /* this also flushes the prefetch-queue */
|
||||
|
||||
/*
|
||||
* page 0 is made non-existent, so that kernel NULL pointer references get
|
||||
* caught. Thus the swapper page directory has been moved to 0x1000
|
||||
*
|
||||
* XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
|
||||
* with the introduction of the compressed boot code. Theoretically,
|
||||
* the original design of overlaying the startup code with the swapper
|
||||
* page directory is still possible --- it would reduce the size of the kernel
|
||||
* by 2-3k. This would be a good thing to do at some point.....
|
||||
*/
|
||||
.org 0x1000
|
||||
_swapper_pg_dir:
|
||||
/*
|
||||
* The page tables are initialized to only 4MB here - the final page
|
||||
* tables are set up later depending on memory size.
|
||||
*/
|
||||
.org 0x2000
|
||||
_pg0:
|
||||
|
||||
.org 0x3000
|
||||
_empty_bad_page:
|
||||
|
||||
.org 0x4000
|
||||
_empty_bad_page_table:
|
||||
|
||||
.org 0x5000
|
||||
_empty_zero_page:
|
||||
|
||||
.org 0x6000
|
||||
/*
|
||||
* tmp_floppy_area is used by the floppy-driver when DMA cannot
|
||||
* reach to a buffer-block. It needs to be aligned, so that it isn't
|
||||
* on a 64kB border.
|
||||
*/
|
||||
_tmp_floppy_area:
|
||||
.fill 1024,1,0
|
||||
/*
|
||||
* floppy_track_buffer is used to buffer one track of floppy data: it
|
||||
* has to be separate from the tmp_floppy area, as otherwise a single-
|
||||
* sector read/write can mess it up. It can contain one full track of
|
||||
* data (18*2*512 bytes).
|
||||
*/
|
||||
_floppy_track_buffer:
|
||||
.fill 512*2*18,1,0
|
||||
|
||||
/* This is the default interrupt "handler" :-) */
|
||||
int_msg:
|
||||
.asciz "Unknown interrupt\n"
|
||||
.align 2
|
||||
ignore_int:
|
||||
cld
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
movl $(KERNEL_DS),%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
mov %ax,%fs
|
||||
pushl $int_msg
|
||||
call _printk
|
||||
popl %eax
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %eax
|
||||
iret
|
||||
|
||||
/*
|
||||
* The interrupt descriptor table has room for 256 idt's
|
||||
*/
|
||||
.align 4
|
||||
.word 0
|
||||
idt_descr:
|
||||
.word 256*8-1 # idt contains 256 entries
|
||||
.long 0xc0000000+_idt
|
||||
|
||||
.align 4
|
||||
_idt:
|
||||
.fill 256,8,0 # idt is uninitialized
|
||||
|
||||
.align 4
|
||||
.word 0
|
||||
gdt_descr:
|
||||
.word (8+2*NR_TASKS)*8-1
|
||||
.long 0xc0000000+_gdt
|
||||
|
||||
/*
|
||||
* This gdt setup gives the kernel a 1GB address space at virtual
|
||||
* address 0xC0000000 - space enough for expansion, I hope.
|
||||
*/
|
||||
.align 4
|
||||
_gdt:
|
||||
.quad 0x0000000000000000 /* NULL descriptor */
|
||||
.quad 0x0000000000000000 /* not used */
|
||||
.quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */
|
||||
.quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */
|
||||
.quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
|
||||
.quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
|
||||
.quad 0x0000000000000000 /* not used */
|
||||
.quad 0x0000000000000000 /* not used */
|
||||
.fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
|
869
source/THIRDPARTY/linux-old/boot/setup.S
Normal file
869
source/THIRDPARTY/linux-old/boot/setup.S
Normal file
|
@ -0,0 +1,869 @@
|
|||
!
|
||||
! setup.S Copyright (C) 1991, 1992 Linus Torvalds
|
||||
!
|
||||
! setup.s is responsible for getting the system data from the BIOS,
|
||||
! and putting them into the appropriate places in system memory.
|
||||
! both setup.s and system has been loaded by the bootblock.
|
||||
!
|
||||
! This code asks the bios for memory/disk/other parameters, and
|
||||
! puts them in a "safe" place: 0x90000-0x901FF, ie where the
|
||||
! boot-block used to be. It is then up to the protected mode
|
||||
! system to read them from there before the area is overwritten
|
||||
! for buffer-blocks.
|
||||
!
|
||||
! Move PS/2 aux init code to psaux.c
|
||||
! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
|
||||
!
|
||||
! some changes and additional features by Christoph Niemann, March 1993
|
||||
! (niemann@rubdv15.ETDV.Ruhr-Uni-Bochum.De)
|
||||
!
|
||||
|
||||
! NOTE! These had better be the same as in bootsect.s!
|
||||
#include <linux/config.h>
|
||||
#include <linux/segment.h>
|
||||
|
||||
#ifndef SVGA_MODE
|
||||
#define SVGA_MODE ASK_VGA
|
||||
#endif
|
||||
|
||||
INITSEG = DEF_INITSEG ! we move boot here - out of the way
|
||||
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
|
||||
SETUPSEG = DEF_SETUPSEG ! this is the current segment
|
||||
|
||||
.globl begtext, begdata, begbss, endtext, enddata, endbss
|
||||
.text
|
||||
begtext:
|
||||
.data
|
||||
begdata:
|
||||
.bss
|
||||
begbss:
|
||||
.text
|
||||
|
||||
entry start
|
||||
start:
|
||||
|
||||
! ok, the read went well so we get current cursor position and save it for
|
||||
! posterity.
|
||||
|
||||
mov ax,#INITSEG ! this is done in bootsect already, but...
|
||||
mov ds,ax
|
||||
|
||||
! Get memory size (extended mem, kB)
|
||||
|
||||
mov ah,#0x88
|
||||
int 0x15
|
||||
mov [2],ax
|
||||
|
||||
! set the keyboard repeat rate to the max
|
||||
|
||||
mov ax,#0x0305
|
||||
xor bx,bx ! clear bx
|
||||
int 0x16
|
||||
|
||||
! check for EGA/VGA and some config parameters
|
||||
|
||||
mov ah,#0x12
|
||||
mov bl,#0x10
|
||||
int 0x10
|
||||
mov [8],ax
|
||||
mov [10],bx
|
||||
mov [12],cx
|
||||
mov ax,#0x5019
|
||||
cmp bl,#0x10
|
||||
je novga
|
||||
mov ax,#0x1a00 ! Added check for EGA/VGA discrimination
|
||||
int 0x10
|
||||
mov bx,ax
|
||||
mov ax,#0x5019
|
||||
cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower
|
||||
jne novga
|
||||
call chsvga
|
||||
novga: mov [14],ax
|
||||
mov ah,#0x03 ! read cursor pos
|
||||
xor bh,bh ! clear bh
|
||||
int 0x10 ! save it in known place, con_init fetches
|
||||
mov [0],dx ! it from 0x90000.
|
||||
|
||||
! Get video-card data:
|
||||
|
||||
mov ah,#0x0f
|
||||
int 0x10
|
||||
mov [4],bx ! bh = display page
|
||||
mov [6],ax ! al = video mode, ah = window width
|
||||
|
||||
! Get hd0 data
|
||||
|
||||
xor ax,ax ! clear ax
|
||||
mov ds,ax
|
||||
lds si,[4*0x41]
|
||||
mov ax,#INITSEG
|
||||
mov es,ax
|
||||
mov di,#0x0080
|
||||
mov cx,#0x10
|
||||
cld
|
||||
rep
|
||||
movsb
|
||||
|
||||
! Get hd1 data
|
||||
|
||||
xor ax,ax ! clear ax
|
||||
mov ds,ax
|
||||
lds si,[4*0x46]
|
||||
mov ax,#INITSEG
|
||||
mov es,ax
|
||||
mov di,#0x0090
|
||||
mov cx,#0x10
|
||||
cld
|
||||
rep
|
||||
movsb
|
||||
|
||||
! Check that there IS a hd1 :-)
|
||||
|
||||
mov ax,#0x01500
|
||||
mov dl,#0x81
|
||||
int 0x13
|
||||
jc no_disk1
|
||||
cmp ah,#3
|
||||
je is_disk1
|
||||
no_disk1:
|
||||
mov ax,#INITSEG
|
||||
mov es,ax
|
||||
mov di,#0x0090
|
||||
mov cx,#0x10
|
||||
xor ax,ax ! clear ax
|
||||
cld
|
||||
rep
|
||||
stosb
|
||||
is_disk1:
|
||||
|
||||
! check for PS/2 pointing device
|
||||
|
||||
mov ax,#INITSEG
|
||||
mov ds,ax
|
||||
mov [0x1ff],#0 ! default is no pointing device
|
||||
int 0x11 ! int 0x11: equipment determination
|
||||
test al,#0x04 ! check if pointing device installed
|
||||
jz no_psmouse
|
||||
mov [0x1ff],#0xaa ! device present
|
||||
no_psmouse:
|
||||
! now we want to move to protected mode ...
|
||||
|
||||
cli ! no interrupts allowed !
|
||||
mov al,#0x80 ! disable NMI for the bootup sequence
|
||||
out #0x70,al
|
||||
|
||||
! first we move the system to its rightful place
|
||||
|
||||
mov ax,#0x100 ! start of destination segment
|
||||
mov bx,#0x1000 ! start of source segment
|
||||
cld ! 'direction'=0, movs moves forward
|
||||
do_move:
|
||||
mov es,ax ! destination segment
|
||||
add ax,#0x100
|
||||
cmp ax,#0x9000
|
||||
jz end_move
|
||||
mov ds,bx ! source segment
|
||||
add bx,#0x100
|
||||
sub di,di
|
||||
sub si,si
|
||||
mov cx,#0x800
|
||||
rep
|
||||
movsw
|
||||
jmp do_move
|
||||
|
||||
! then we load the segment descriptors
|
||||
|
||||
end_move:
|
||||
mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
|
||||
mov ds,ax
|
||||
lidt idt_48 ! load idt with 0,0
|
||||
lgdt gdt_48 ! load gdt with whatever appropriate
|
||||
|
||||
! that was painless, now we enable A20
|
||||
|
||||
call empty_8042
|
||||
mov al,#0xD1 ! command write
|
||||
out #0x64,al
|
||||
call empty_8042
|
||||
mov al,#0xDF ! A20 on
|
||||
out #0x60,al
|
||||
call empty_8042
|
||||
|
||||
! make sure any possible coprocessor is properly reset..
|
||||
|
||||
xor ax,ax
|
||||
out #0xf0,al
|
||||
call delay
|
||||
out #0xf1,al
|
||||
call delay
|
||||
|
||||
! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
|
||||
! we put them right after the intel-reserved hardware interrupts, at
|
||||
! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
|
||||
! messed this up with the original PC, and they haven't been able to
|
||||
! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
|
||||
! which is used for the internal hardware interrupts as well. We just
|
||||
! have to reprogram the 8259's, and it isn't fun.
|
||||
|
||||
mov al,#0x11 ! initialization sequence
|
||||
out #0x20,al ! send it to 8259A-1
|
||||
call delay
|
||||
out #0xA0,al ! and to 8259A-2
|
||||
call delay
|
||||
mov al,#0x20 ! start of hardware int's (0x20)
|
||||
out #0x21,al
|
||||
call delay
|
||||
mov al,#0x28 ! start of hardware int's 2 (0x28)
|
||||
out #0xA1,al
|
||||
call delay
|
||||
mov al,#0x04 ! 8259-1 is master
|
||||
out #0x21,al
|
||||
call delay
|
||||
mov al,#0x02 ! 8259-2 is slave
|
||||
out #0xA1,al
|
||||
call delay
|
||||
mov al,#0x01 ! 8086 mode for both
|
||||
out #0x21,al
|
||||
call delay
|
||||
out #0xA1,al
|
||||
call delay
|
||||
mov al,#0xFF ! mask off all interrupts for now
|
||||
out #0xA1,al
|
||||
call delay
|
||||
mov al,#0xFB ! mask all irq's but irq2 which
|
||||
out #0x21,al ! is cascaded
|
||||
|
||||
! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
|
||||
! need no steenking BIOS anyway (except for the initial loading :-).
|
||||
! The BIOS-routine wants lots of unnecessary data, and it's less
|
||||
! "interesting" anyway. This is how REAL programmers do it.
|
||||
!
|
||||
! Well, now's the time to actually move into protected mode. To make
|
||||
! things as simple as possible, we do no register set-up or anything,
|
||||
! we let the gnu-compiled 32-bit programs do that. We just jump to
|
||||
! absolute address 0x00000, in 32-bit protected mode.
|
||||
!
|
||||
! Note that the short jump isn't strictly needed, althought there are
|
||||
! reasons why it might be a good idea. It won't hurt in any case.
|
||||
!
|
||||
mov ax,#0x0001 ! protected mode (PE) bit
|
||||
lmsw ax ! This is it!
|
||||
jmp flush_instr
|
||||
flush_instr:
|
||||
jmpi 0x1000,KERNEL_CS ! jmp offset 1000 of segment 0x10 (cs)
|
||||
|
||||
! This routine checks that the keyboard command queue is empty
|
||||
! (after emptying the output buffers)
|
||||
!
|
||||
! No timeout is used - if this hangs there is something wrong with
|
||||
! the machine, and we probably couldn't proceed anyway.
|
||||
empty_8042:
|
||||
call delay
|
||||
in al,#0x64 ! 8042 status port
|
||||
test al,#1 ! output buffer?
|
||||
jz no_output
|
||||
call delay
|
||||
in al,#0x60 ! read it
|
||||
jmp empty_8042
|
||||
no_output:
|
||||
test al,#2 ! is input buffer full?
|
||||
jnz empty_8042 ! yes - loop
|
||||
ret
|
||||
!
|
||||
! Read a key and return the (US-)ascii code in al, scan code in ah
|
||||
!
|
||||
getkey:
|
||||
xor ah,ah
|
||||
int 0x16
|
||||
ret
|
||||
|
||||
!
|
||||
! Read a key with a timeout of 30 seconds. The cmos clock is used to get
|
||||
! the time.
|
||||
!
|
||||
getkt:
|
||||
call gettime
|
||||
add al,#30 ! wait 30 seconds
|
||||
cmp al,#60
|
||||
jl lminute
|
||||
sub al,#60
|
||||
lminute:
|
||||
mov cl,al
|
||||
again: mov ah,#0x01
|
||||
int 0x16
|
||||
jnz getkey ! key pressed, so get it
|
||||
call gettime
|
||||
cmp al,cl
|
||||
jne again
|
||||
mov al,#0x20 ! timeout, return default char `space'
|
||||
ret
|
||||
|
||||
!
|
||||
! Flush the keyboard buffer
|
||||
!
|
||||
flush: mov ah,#0x01
|
||||
int 0x16
|
||||
jz empty
|
||||
xor ah,ah
|
||||
int 0x16
|
||||
jmp flush
|
||||
empty: ret
|
||||
|
||||
!
|
||||
! Read the cmos clock. Return the seconds in al
|
||||
!
|
||||
gettime:
|
||||
push cx
|
||||
mov ah,#0x02
|
||||
int 0x1a
|
||||
mov al,dh ! dh contains the seconds
|
||||
and al,#0x0f
|
||||
mov ah,dh
|
||||
mov cl,#0x04
|
||||
shr ah,cl
|
||||
aad
|
||||
pop cx
|
||||
ret
|
||||
|
||||
!
|
||||
! Delay is needed after doing i/o
|
||||
!
|
||||
delay:
|
||||
.word 0x00eb ! jmp $+2
|
||||
ret
|
||||
|
||||
! Routine trying to recognize type of SVGA-board present (if any)
|
||||
! and if it recognize one gives the choices of resolution it offers.
|
||||
! If one is found the resolution chosen is given by al,ah (rows,cols).
|
||||
|
||||
chsvga: cld
|
||||
push ds
|
||||
push cs
|
||||
mov ax,[0x01fa]
|
||||
pop ds
|
||||
mov modesave,ax
|
||||
mov ax,#0xc000
|
||||
mov es,ax
|
||||
mov ax,modesave
|
||||
cmp ax,#NORMAL_VGA
|
||||
je defvga
|
||||
cmp ax,#EXTENDED_VGA
|
||||
je vga50
|
||||
cmp ax,#ASK_VGA
|
||||
jne svga
|
||||
lea si,msg1
|
||||
call prtstr
|
||||
call flush
|
||||
nokey: call getkt
|
||||
cmp al,#0x0d ! enter ?
|
||||
je svga ! yes - svga selection
|
||||
cmp al,#0x20 ! space ?
|
||||
je defvga ! no - repeat
|
||||
call beep
|
||||
jmp nokey
|
||||
defvga: mov ax,#0x5019
|
||||
pop ds
|
||||
ret
|
||||
/* extended vga mode: 80x50 */
|
||||
vga50:
|
||||
mov ax,#0x1112
|
||||
xor bl,bl
|
||||
int 0x10 ! use 8x8 font set (50 lines on VGA)
|
||||
mov ax,#0x1200
|
||||
mov bl,#0x20
|
||||
int 0x10 ! use alternate print screen
|
||||
mov ax,#0x1201
|
||||
mov bl,#0x34
|
||||
int 0x10 ! turn off cursor emulation
|
||||
mov ah,#0x01
|
||||
mov cx,#0x0607
|
||||
int 0x10 ! turn on cursor (scan lines 6 to 7)
|
||||
pop ds
|
||||
mov ax,#0x5032 ! return 80x50
|
||||
ret
|
||||
/* extended vga mode: 80x28 */
|
||||
vga28:
|
||||
pop ax ! clean the stack
|
||||
mov ax,#0x1111
|
||||
xor bl,bl
|
||||
int 0x10 ! use 9x14 fontset (28 lines on VGA)
|
||||
mov ah, #0x01
|
||||
mov cx,#0x0b0c
|
||||
int 0x10 ! turn on cursor (scan lines 11 to 12)
|
||||
pop ds
|
||||
mov ax,#0x501c ! return 80x28
|
||||
ret
|
||||
/* svga modes */
|
||||
svga: cld
|
||||
lea si,id9GXE ! Check for the #9GXE (jyanowit@orixa.mtholyoke.edu,thanks dlm40629@uxa.cso.uiuc.edu)
|
||||
mov di,#0x49 ! id string is at c000:049
|
||||
mov cx,#0x11 ! length of "Graphics Power By"
|
||||
repe
|
||||
cmpsb
|
||||
jne of1280
|
||||
is9GXE: lea si,dsc9GXE ! table of descriptions of video modes for BIOS
|
||||
lea di,mo9GXE ! table of sizes of video modes for my BIOS
|
||||
br selmod ! go ask for video mode
|
||||
of1280: cld
|
||||
lea si,idf1280 ! Check for Orchid F1280 (dingbat@diku.dk)
|
||||
mov di,#0x10a ! id string is at c000:010a
|
||||
mov cx,#0x21 ! length
|
||||
repe
|
||||
cmpsb
|
||||
jne nf1280
|
||||
isVRAM: lea si,dscf1280
|
||||
lea di,mof1280
|
||||
br selmod
|
||||
nf1280: lea si,idVRAM
|
||||
mov di,#0x10a
|
||||
mov cx,#0x0c
|
||||
repe
|
||||
cmpsb
|
||||
je isVRAM
|
||||
cld
|
||||
lea si,idati ! Check ATI 'clues'
|
||||
mov di,#0x31
|
||||
mov cx,#0x09
|
||||
repe
|
||||
cmpsb
|
||||
jne noati
|
||||
lea si,dscati
|
||||
lea di,moati
|
||||
br selmod
|
||||
noati: mov ax,#0x200f ! Check Ahead 'clues'
|
||||
mov dx,#0x3ce
|
||||
out dx,ax
|
||||
inc dx
|
||||
in al,dx
|
||||
cmp al,#0x20
|
||||
je isahed
|
||||
cmp al,#0x21
|
||||
jne noahed
|
||||
isahed: lea si,dscahead
|
||||
lea di,moahead
|
||||
br selmod
|
||||
noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues'
|
||||
in al,dx
|
||||
or al,#0x10
|
||||
out dx,al
|
||||
mov dx,#0x104
|
||||
in al,dx
|
||||
mov bl,al
|
||||
mov dx,#0x3c3
|
||||
in al,dx
|
||||
and al,#0xef
|
||||
out dx,al
|
||||
cmp bl,[idcandt]
|
||||
jne nocant
|
||||
lea si,dsccandt
|
||||
lea di,mocandt
|
||||
br selmod
|
||||
nocant: mov dx,#0x3d4 ! Check Cirrus 'clues'
|
||||
mov al,#0x0c
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
mov bl,al
|
||||
xor al,al
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,#0x1f
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
mov bh,al
|
||||
xor ah,ah
|
||||
shl al,#4
|
||||
mov cx,ax
|
||||
mov al,bh
|
||||
shr al,#4
|
||||
add cx,ax
|
||||
shl cx,#8
|
||||
add cx,#6
|
||||
mov ax,cx
|
||||
mov dx,#0x3c4
|
||||
out dx,ax
|
||||
inc dx
|
||||
in al,dx
|
||||
and al,al
|
||||
jnz nocirr
|
||||
mov al,bh
|
||||
out dx,al
|
||||
in al,dx
|
||||
cmp al,#0x01
|
||||
jne nocirr
|
||||
call rst3d4
|
||||
lea si,dsccirrus
|
||||
lea di,mocirrus
|
||||
br selmod
|
||||
rst3d4: mov dx,#0x3d4
|
||||
mov al,bl
|
||||
xor ah,ah
|
||||
shl ax,#8
|
||||
add ax,#0x0c
|
||||
out dx,ax
|
||||
ret
|
||||
nocirr: call rst3d4 ! Check Everex 'clues'
|
||||
mov ax,#0x7000
|
||||
xor bx,bx
|
||||
int 0x10
|
||||
cmp al,#0x70
|
||||
jne noevrx
|
||||
shr dx,#4
|
||||
cmp dx,#0x678
|
||||
je istrid
|
||||
cmp dx,#0x236
|
||||
je istrid
|
||||
lea si,dsceverex
|
||||
lea di,moeverex
|
||||
br selmod
|
||||
istrid: lea cx,ev2tri
|
||||
jmp cx
|
||||
noevrx: lea si,idgenoa ! Check Genoa 'clues'
|
||||
xor ax,ax
|
||||
seg es
|
||||
mov al,[0x37]
|
||||
mov di,ax
|
||||
mov cx,#0x04
|
||||
dec si
|
||||
dec di
|
||||
l1: inc si
|
||||
inc di
|
||||
mov al,(si)
|
||||
test al,al
|
||||
jz l2
|
||||
seg es
|
||||
cmp al,(di)
|
||||
l2: loope l1
|
||||
cmp cx,#0x00
|
||||
jne nogen
|
||||
lea si,dscgenoa
|
||||
lea di,mogenoa
|
||||
br selmod
|
||||
nogen: cld
|
||||
lea si,idoakvga
|
||||
mov di,#0x08
|
||||
mov cx,#0x08
|
||||
repe
|
||||
cmpsb
|
||||
jne nooak
|
||||
lea si,dscoakvga
|
||||
lea di,mooakvga
|
||||
br selmod
|
||||
nooak: cld
|
||||
lea si,idparadise ! Check Paradise 'clues'
|
||||
mov di,#0x7d
|
||||
mov cx,#0x04
|
||||
repe
|
||||
cmpsb
|
||||
jne nopara
|
||||
lea si,dscparadise
|
||||
lea di,moparadise
|
||||
br selmod
|
||||
nopara: mov dx,#0x3c4 ! Check Trident 'clues'
|
||||
mov al,#0x0e
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
xchg ah,al
|
||||
xor al,al
|
||||
out dx,al
|
||||
in al,dx
|
||||
xchg al,ah
|
||||
mov bl,al ! Strange thing ... in the book this wasn't
|
||||
and bl,#0x02 ! necessary but it worked on my card which
|
||||
jz setb2 ! is a trident. Without it the screen goes
|
||||
and al,#0xfd ! blurred ...
|
||||
jmp clrb2 !
|
||||
setb2: or al,#0x02 !
|
||||
clrb2: out dx,al
|
||||
and ah,#0x0f
|
||||
cmp ah,#0x02
|
||||
jne notrid
|
||||
ev2tri: lea si,dsctrident
|
||||
lea di,motrident
|
||||
jmp selmod
|
||||
notrid: mov dx,#0x3cd ! Check Tseng 'clues'
|
||||
in al,dx ! Could things be this simple ! :-)
|
||||
mov bl,al
|
||||
mov al,#0x55
|
||||
out dx,al
|
||||
in al,dx
|
||||
mov ah,al
|
||||
mov al,bl
|
||||
out dx,al
|
||||
cmp ah,#0x55
|
||||
jne notsen
|
||||
lea si,dsctseng
|
||||
lea di,motseng
|
||||
jmp selmod
|
||||
notsen: mov dx,#0x3cc ! Check Video7 'clues'
|
||||
in al,dx
|
||||
mov dx,#0x3b4
|
||||
and al,#0x01
|
||||
jz even7
|
||||
mov dx,#0x3d4
|
||||
even7: mov al,#0x0c
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
mov bl,al
|
||||
mov al,#0x55
|
||||
out dx,al
|
||||
in al,dx
|
||||
dec dx
|
||||
mov al,#0x1f
|
||||
out dx,al
|
||||
inc dx
|
||||
in al,dx
|
||||
mov bh,al
|
||||
dec dx
|
||||
mov al,#0x0c
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,bl
|
||||
out dx,al
|
||||
mov al,#0x55
|
||||
xor al,#0xea
|
||||
cmp al,bh
|
||||
jne novid7
|
||||
lea si,dscvideo7
|
||||
lea di,movideo7
|
||||
jmp selmod
|
||||
novid7: lea si,dsunknown
|
||||
lea di,mounknown
|
||||
selmod: xor cx,cx
|
||||
mov cl,(di)
|
||||
mov ax,modesave
|
||||
cmp ax,#ASK_VGA
|
||||
je askmod
|
||||
cmp ax,#NORMAL_VGA
|
||||
je askmod
|
||||
cmp al,cl
|
||||
jl gotmode
|
||||
push si
|
||||
lea si,msg4
|
||||
call prtstr
|
||||
pop si
|
||||
askmod: push si
|
||||
lea si,msg2
|
||||
call prtstr
|
||||
pop si
|
||||
push si
|
||||
push cx
|
||||
tbl: pop bx
|
||||
push bx
|
||||
mov al,bl
|
||||
sub al,cl
|
||||
call modepr
|
||||
lodsw
|
||||
xchg al,ah
|
||||
call dprnt
|
||||
xchg ah,al
|
||||
push ax
|
||||
mov al,#0x78
|
||||
call prnt1
|
||||
pop ax
|
||||
call dprnt
|
||||
push si
|
||||
lea si,crlf ! print CR+LF
|
||||
call prtstr
|
||||
pop si
|
||||
loop tbl
|
||||
pop cx
|
||||
lea si,msg3
|
||||
call prtstr
|
||||
pop si
|
||||
add cl,#0x30
|
||||
jmp nonum
|
||||
nonumb: call beep
|
||||
nonum: call getkey
|
||||
cmp al,#0x30 ! ascii `0'
|
||||
jb nonumb
|
||||
cmp al,#0x3a ! ascii `9'
|
||||
jbe number
|
||||
cmp al,#0x61 ! ascii `a'
|
||||
jb nonumb
|
||||
cmp al,#0x7a ! ascii `z'
|
||||
ja nonumb
|
||||
sub al,#0x27
|
||||
cmp al,cl
|
||||
jae nonumb
|
||||
sub al,#0x30
|
||||
jmp gotmode
|
||||
number: cmp al,cl
|
||||
jae nonumb
|
||||
sub al,#0x30
|
||||
gotmode: xor ah,ah
|
||||
or al,al
|
||||
beq vga50
|
||||
push ax
|
||||
dec ax
|
||||
beq vga28
|
||||
add di,ax
|
||||
mov al,(di)
|
||||
int 0x10
|
||||
pop ax
|
||||
shl ax,#1
|
||||
add si,ax
|
||||
lodsw
|
||||
pop ds
|
||||
ret
|
||||
|
||||
! Routine to print asciiz-string at DS:SI
|
||||
|
||||
prtstr: lodsb
|
||||
and al,al
|
||||
jz fin
|
||||
call prnt1
|
||||
jmp prtstr
|
||||
fin: ret
|
||||
|
||||
! Routine to print a decimal value on screen, the value to be
|
||||
! printed is put in al (i.e 0-255).
|
||||
|
||||
dprnt: push ax
|
||||
push cx
|
||||
xor ah,ah ! Clear ah
|
||||
mov cl,#0x0a
|
||||
idiv cl
|
||||
cmp al,#0x09
|
||||
jbe lt100
|
||||
call dprnt
|
||||
jmp skip10
|
||||
lt100: add al,#0x30
|
||||
call prnt1
|
||||
skip10: mov al,ah
|
||||
add al,#0x30
|
||||
call prnt1
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
!
|
||||
! Routine to print the mode number key on screen. Mode numbers
|
||||
! 0-9 print the ascii values `0' to '9', 10-35 are represented by
|
||||
! the letters `a' to `z'. This routine prints some spaces around the
|
||||
! mode no.
|
||||
!
|
||||
|
||||
modepr: push ax
|
||||
cmp al,#0x0a
|
||||
jb digit ! Here is no check for number > 35
|
||||
add al,#0x27
|
||||
digit: add al,#0x30
|
||||
mov modenr, al
|
||||
push si
|
||||
lea si, modestring
|
||||
call prtstr
|
||||
pop si
|
||||
pop ax
|
||||
ret
|
||||
|
||||
! Part of above routine, this one just prints ascii al
|
||||
|
||||
prnt1: push ax
|
||||
push cx
|
||||
xor bh,bh
|
||||
mov cx,#0x01
|
||||
mov ah,#0x0e
|
||||
int 0x10
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
beep: mov al,#0x07
|
||||
jmp prnt1
|
||||
|
||||
gdt:
|
||||
.word 0,0,0,0 ! dummy
|
||||
|
||||
.word 0,0,0,0 ! unused
|
||||
|
||||
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
|
||||
.word 0x0000 ! base address=0
|
||||
.word 0x9A00 ! code read/exec
|
||||
.word 0x00C0 ! granularity=4096, 386
|
||||
|
||||
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
|
||||
.word 0x0000 ! base address=0
|
||||
.word 0x9200 ! data read/write
|
||||
.word 0x00C0 ! granularity=4096, 386
|
||||
|
||||
idt_48:
|
||||
.word 0 ! idt limit=0
|
||||
.word 0,0 ! idt base=0L
|
||||
|
||||
gdt_48:
|
||||
.word 0x800 ! gdt limit=2048, 256 GDT entries
|
||||
.word 512+gdt,0x9 ! gdt base = 0X9xxxx
|
||||
|
||||
msg1: .ascii "Press <RETURN> to see SVGA-modes available, <SPACE> to continue or wait 30 secs."
|
||||
db 0x0d, 0x0a, 0x0a, 0x00
|
||||
msg2: .ascii "Mode: COLSxROWS:"
|
||||
db 0x0d, 0x0a, 0x0a, 0x00
|
||||
msg3: db 0x0d, 0x0a
|
||||
.ascii "Choose mode by pressing the corresponding number or letter."
|
||||
crlf: db 0x0d, 0x0a, 0x00
|
||||
msg4: .ascii "You passed an undefined mode number to setup. Please choose a new mode."
|
||||
db 0x0d, 0x0a, 0x0a, 0x07, 0x00
|
||||
modestring: .ascii " "
|
||||
modenr: db 0x00 ! mode number
|
||||
.ascii ": "
|
||||
db 0x00
|
||||
|
||||
idati: .ascii "761295520"
|
||||
idcandt: .byte 0xa5
|
||||
idgenoa: .byte 0x77, 0x00, 0x99, 0x66
|
||||
idparadise: .ascii "VGA="
|
||||
idoakvga: .ascii "OAK VGA "
|
||||
idf1280: .ascii "Orchid Technology Fahrenheit 1280"
|
||||
id9GXE: .ascii "Graphics Power By"
|
||||
idVRAM: .ascii "Stealth VRAM"
|
||||
|
||||
! Manufacturer: Numofmodes+2: Mode:
|
||||
! Number of modes is the number of chip-specific svga modes plus the extended
|
||||
! modes available on any vga (currently 2)
|
||||
|
||||
moati: .byte 0x04, 0x23, 0x33
|
||||
moahead: .byte 0x07, 0x22, 0x23, 0x24, 0x2f, 0x34
|
||||
mocandt: .byte 0x04, 0x60, 0x61
|
||||
mocirrus: .byte 0x06, 0x1f, 0x20, 0x22, 0x31
|
||||
moeverex: .byte 0x0c, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40
|
||||
mogenoa: .byte 0x0c, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78
|
||||
moparadise: .byte 0x04, 0x55, 0x54
|
||||
motrident: .byte 0x09, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
|
||||
motseng: .byte 0x07, 0x26, 0x2a, 0x23, 0x24, 0x22
|
||||
movideo7: .byte 0x08, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
|
||||
mooakvga: .byte 0x08, 0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51
|
||||
mo9GXE: .byte 0x04, 0x54, 0x55
|
||||
mof1280: .byte 0x04, 0x54, 0x55
|
||||
mounknown: .byte 0x02
|
||||
|
||||
! msb = Cols lsb = Rows:
|
||||
! The first two modes are standard vga modes available on any vga.
|
||||
! mode 0 is 80x50 and mode 1 is 80x28
|
||||
|
||||
dscati: .word 0x5032, 0x501c, 0x8419, 0x842c
|
||||
dscahead: .word 0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042
|
||||
dsccandt: .word 0x5032, 0x501c, 0x8419, 0x8432
|
||||
dsccirrus: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425
|
||||
dsceverex: .word 0x5032, 0x501c, 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e
|
||||
dscgenoa: .word 0x5032, 0x501c, 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b
|
||||
dscparadise: .word 0x5032, 0x501c, 0x8419, 0x842b
|
||||
dsctrident: .word 0x5032, 0x501c, 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
|
||||
dsctseng: .word 0x5032, 0x501c, 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
|
||||
dscvideo7: .word 0x5032, 0x501c, 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
|
||||
dscoakvga: .word 0x5032, 0x501c, 0x2819, 0x5019, 0x503c, 0x843c, 0x8419, 0x842b
|
||||
dscf1280: .word 0x5032, 0x501c, 0x842b, 0x8419
|
||||
dsc9GXE: .word 0x5032, 0x501c, 0x842b, 0x8419
|
||||
dsunknown: .word 0x5032, 0x501c
|
||||
modesave: .word SVGA_MODE
|
||||
|
||||
|
||||
.text
|
||||
endtext:
|
||||
.data
|
||||
enddata:
|
||||
.bss
|
||||
endbss:
|
139
source/THIRDPARTY/linux-old/config.in
Normal file
139
source/THIRDPARTY/linux-old/config.in
Normal file
|
@ -0,0 +1,139 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the Configure script.
|
||||
#
|
||||
*
|
||||
* General setup
|
||||
*
|
||||
bool 'Kernel math emulation' CONFIG_MATH_EMULATION y
|
||||
bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y
|
||||
bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
|
||||
bool 'TCP/IP networking' CONFIG_INET y
|
||||
bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
|
||||
bool 'System V IPC' CONFIG_SYSVIPC y
|
||||
bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
|
||||
*
|
||||
* Program binary formats
|
||||
*
|
||||
bool 'Elf executables' CONFIG_BINFMT_ELF y
|
||||
bool 'COFF executables' CONFIG_BINFMT_COFF y
|
||||
*
|
||||
* SCSI support
|
||||
*
|
||||
bool 'SCSI support?' CONFIG_SCSI n
|
||||
if [ "$CONFIG_SCSI" = "n" ]
|
||||
:
|
||||
: Skipping SCSI configuration options...
|
||||
:
|
||||
else
|
||||
*
|
||||
* SCSI support type (disk, tape, CDrom)
|
||||
*
|
||||
bool 'Scsi disk support' CONFIG_BLK_DEV_SD y
|
||||
bool 'Scsi tape support' CONFIG_CHR_DEV_ST y
|
||||
bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR y
|
||||
bool 'Scsi generic support' CONFIG_CHR_DEV_SG y
|
||||
*
|
||||
* SCSI low-level drivers
|
||||
*
|
||||
bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
|
||||
bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
|
||||
bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
|
||||
bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN y
|
||||
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 y
|
||||
bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 y
|
||||
bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE y
|
||||
bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 y
|
||||
bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR y
|
||||
bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST y
|
||||
fi
|
||||
*
|
||||
* Network device support
|
||||
*
|
||||
bool 'Network device support?' CONFIG_ETHERCARDS y
|
||||
if [ "$CONFIG_ETHERCARDS" = "n" ]
|
||||
:
|
||||
: Skipping ethercard configuration options...
|
||||
:
|
||||
else
|
||||
bool 'SLIP (serial line) support' CONFIG_SLIP n
|
||||
if [ "$CONFIG_SLIP" = "y" ]
|
||||
bool ' CSLIP compressed headers' SL_COMPRESSED y
|
||||
# bool ' SLIP debugging on' SL_DUMP y
|
||||
fi
|
||||
#bool 'PPP (point-to-point) support' CONFIG_PPP n
|
||||
bool 'PLIP (parallel port) support' CONFIG_PLIP n
|
||||
bool 'NE2000/NE1000 support' CONFIG_NE2000 n
|
||||
bool 'WD80*3 support' CONFIG_WD80x3 y
|
||||
bool 'SMC Ultra support' CONFIG_ULTRA n
|
||||
bool '3c501 support' CONFIG_EL1 n
|
||||
bool '3c503 support' CONFIG_EL2 n
|
||||
#bool '3c505 support' CONFIG_ELPLUS n
|
||||
#bool '3c507 support' CONFIG_EL16 n
|
||||
bool '3c509/3c579 support' CONFIG_EL3 n
|
||||
bool 'HP PCLAN support' CONFIG_HPLAN n
|
||||
bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
|
||||
bool 'AT1700 support' CONFIG_AT1700 n
|
||||
#bool 'Zenith Z-Note support' CONFIG_ZNET n
|
||||
#bool 'EtherExpress support' CONFIG_EEXPRESS n
|
||||
#bool 'DEPCA support' CONFIG_DEPCA n
|
||||
#bool 'NI52** support' CONFIG_NI52 n
|
||||
#bool 'NI65** support' CONFIG_NI65 n
|
||||
#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
|
||||
#bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n
|
||||
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
|
||||
bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
|
||||
fi
|
||||
*
|
||||
bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n
|
||||
bool 'Mitsumi CDROM driver support' CONFIG_MCD n
|
||||
bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
|
||||
*
|
||||
* Filesystems
|
||||
*
|
||||
bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
|
||||
bool 'Extended fs support' CONFIG_EXT_FS n
|
||||
bool 'Second extended fs support' CONFIG_EXT2_FS y
|
||||
bool 'xiafs filesystem support' CONFIG_XIA_FS n
|
||||
bool 'msdos fs support' CONFIG_MSDOS_FS y
|
||||
bool '/proc filesystem support' CONFIG_PROC_FS y
|
||||
bool 'NFS filesystem support' CONFIG_NFS_FS y
|
||||
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
|
||||
bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
|
||||
bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
|
||||
*
|
||||
* character devices
|
||||
*
|
||||
#bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
|
||||
#bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
|
||||
bool 'Parallel printer support' CONFIG_PRINTER y
|
||||
bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
|
||||
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y
|
||||
if [ "$CONFIG_PSMOUSE" = "y" ]
|
||||
bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
|
||||
fi
|
||||
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
|
||||
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
|
||||
bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y
|
||||
bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n
|
||||
bool 'QIC-117 tape support' CONFIG_FTAPE n
|
||||
if [ "$CONFIG_FTAPE" = "y" ]
|
||||
int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
|
||||
fi
|
||||
*
|
||||
* Sound
|
||||
*
|
||||
bool 'Sound card support' CONFIG_SOUND n
|
||||
*
|
||||
* Kernel hacking
|
||||
*
|
||||
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
|
||||
bool 'Kernel profiling support' CONFIG_PROFILE n
|
||||
if [ "$CONFIG_SCSI" = "y" ]
|
||||
bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
|
||||
fi
|
||||
if [ "$CONFIG_SOUND" = "y" ]
|
||||
exec touch .makesound
|
||||
else
|
||||
exec rm -f .makesound
|
||||
fi
|
50
source/THIRDPARTY/linux-old/drivers/FPU-emu/Makefile
Normal file
50
source/THIRDPARTY/linux-old/drivers/FPU-emu/Makefile
Normal file
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# Makefile for wm-FPU-emu
|
||||
#
|
||||
|
||||
#DEBUG = -DDEBUGGING
|
||||
DEBUG =
|
||||
PARANOID = -DPARANOID
|
||||
REENTRANT = -DREENTRANT_FPU
|
||||
CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
|
||||
|
||||
.S.o:
|
||||
$(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $<
|
||||
|
||||
OBJS = fpu_entry.o div_small.o errors.o \
|
||||
fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
|
||||
load_store.o get_address.o \
|
||||
poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
|
||||
poly_div.o poly_mul64.o polynomial.o \
|
||||
reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o \
|
||||
reg_div.o reg_mul.o reg_norm.o \
|
||||
reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \
|
||||
reg_round.o \
|
||||
wm_shrx.o wm_sqrt.o
|
||||
|
||||
math.a: $(OBJS)
|
||||
rm -f math.a
|
||||
$(AR) rcs math.a $(OBJS)
|
||||
sync
|
||||
|
||||
dep:
|
||||
$(CPP) -M *.c > .depend
|
||||
$(CPP) -D__ASSEMBLER__ -M *.S >> .depend
|
||||
|
||||
proto:
|
||||
cproto -e -DMAKING_PROTO *.c >fpu_proto.h
|
||||
|
||||
dummy:
|
||||
|
||||
#
|
||||
# include a dependency file if one exists
|
||||
#
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
include .depend
|
||||
endif
|
312
source/THIRDPARTY/linux-old/drivers/FPU-emu/README
Normal file
312
source/THIRDPARTY/linux-old/drivers/FPU-emu/README
Normal file
|
@ -0,0 +1,312 @@
|
|||
+---------------------------------------------------------------------------+
|
||||
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or modify |
|
||||
| it under the terms of the GNU General Public License version 2 as |
|
||||
| published by the Free Software Foundation. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU General Public License |
|
||||
| along with this program; if not, write to the Free Software |
|
||||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||
| |
|
||||
+---------------------------------------------------------------------------+
|
||||
|
||||
|
||||
|
||||
wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
|
||||
which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was
|
||||
in turn based upon emu387 which was written by DJ Delorie for djgpp.
|
||||
The interface to the Linux kernel is based upon the original Linux
|
||||
math emulator by Linus Torvalds.
|
||||
|
||||
My target FPU for wm-FPU-emu is that described in the Intel486
|
||||
Programmer's Reference Manual (1992 edition). Unfortunately, numerous
|
||||
facets of the functioning of the FPU are not well covered in the
|
||||
Reference Manual. The information in the manual has been supplemented
|
||||
with measurements on real 80486's. Unfortunately, it is simply not
|
||||
possible to be sure that all of the peculiarities of the 80486 have
|
||||
been discovered, so there is always likely to be obscure differences
|
||||
in the detailed behaviour of the emulator and a real 80486.
|
||||
|
||||
wm-FPU-emu does not implement all of the behaviour of the 80486 FPU.
|
||||
See "Limitations" later in this file for a list of some differences.
|
||||
|
||||
Please report bugs, etc to me at:
|
||||
billm@vaxc.cc.monash.edu.au
|
||||
or at:
|
||||
billm@jacobi.maths.monash.edu.au
|
||||
|
||||
|
||||
--Bill Metzenthen
|
||||
Jan 1994
|
||||
|
||||
|
||||
----------------------- Internals of wm-FPU-emu -----------------------
|
||||
|
||||
Numeric algorithms:
|
||||
(1) Add, subtract, and multiply. Nothing remarkable in these.
|
||||
(2) Divide has been tuned to get reasonable performance. The algorithm
|
||||
is not the obvious one which most people seem to use, but is designed
|
||||
to take advantage of the characteristics of the 80386. I expect that
|
||||
it has been invented many times before I discovered it, but I have not
|
||||
seen it. It is based upon one of those ideas which one carries around
|
||||
for years without ever bothering to check it out.
|
||||
(3) The sqrt function has been tuned to get good performance. It is based
|
||||
upon Newton's classic method. Performance was improved by capitalizing
|
||||
upon the properties of Newton's method, and the code is once again
|
||||
structured taking account of the 80386 characteristics.
|
||||
(4) The trig, log, and exp functions are based in each case upon quasi-
|
||||
"optimal" polynomial approximations. My definition of "optimal" was
|
||||
based upon getting good accuracy with reasonable speed.
|
||||
(5) The argument reducing code for the trig function effectively uses
|
||||
a value of pi which is accurate to more than 128 bits. As a consequence,
|
||||
the reduced argument is accurate to more than 64 bits for arguments up
|
||||
to a few pi, and accurate to more than 64 bits for most arguments,
|
||||
even for arguments approaching 2^63. This is far superior to an
|
||||
80486, which uses a value of pi which is accurate to 66 bits.
|
||||
|
||||
The code of the emulator is complicated slightly by the need to
|
||||
account for a limited form of re-entrancy. Normally, the emulator will
|
||||
emulate each FPU instruction to completion without interruption.
|
||||
However, it may happen that when the emulator is accessing the user
|
||||
memory space, swapping may be needed. In this case the emulator may be
|
||||
temporarily suspended while disk i/o takes place. During this time
|
||||
another process may use the emulator, thereby changing some static
|
||||
variables (eg FPU_st0_ptr, etc). The code which accesses user memory
|
||||
is confined to five files:
|
||||
fpu_entry.c
|
||||
reg_ld_str.c
|
||||
load_store.c
|
||||
get_address.c
|
||||
errors.c
|
||||
|
||||
----------------------- Limitations of wm-FPU-emu -----------------------
|
||||
|
||||
There are a number of differences between the current wm-FPU-emu
|
||||
(version beta 1.5) and the 80486 FPU (apart from bugs). Some of the
|
||||
more important differences are listed below:
|
||||
|
||||
Segment overrides don't do anything yet.
|
||||
|
||||
All internal computations are performed at 64 bit or higher precision
|
||||
and the results rounded etc as required by the PC bits of the FPU
|
||||
control word. Under the crt0 version for Linux current at June 1993,
|
||||
the FPU PC bits specify 64 bits precision.
|
||||
|
||||
The precision flag (PE of the FPU status word) and the Roundup flag
|
||||
(C1 of the status word) are now implemented. Does anyone write code
|
||||
which uses these features? The Roundup flag does not have much meaning
|
||||
for the transcendental functions and its 80486 value with these
|
||||
functions is likely to differ from its emulator value.
|
||||
|
||||
In a few rare cases the Underflow flag obtained with the emulator will
|
||||
be different from that obtained with an 80486. This occurs when the
|
||||
following conditions apply simultaneously:
|
||||
(a) the operands have a higher precision than the current setting of the
|
||||
precision control (PC) flags.
|
||||
(b) the underflow exception is masked.
|
||||
(c) the magnitude of the exact result (before rounding) is less than 2^-16382.
|
||||
(d) the magnitude of the final result (after rounding) is exactly 2^-16382.
|
||||
(e) the magnitude of the exact result would be exactly 2^-16382 if the
|
||||
operands were rounded to the current precision before the arithmetic
|
||||
operation was performed.
|
||||
If all of these apply, the emulator will set the Underflow flag but a real
|
||||
80486 will not.
|
||||
|
||||
NOTE: Certain formats of Extended Real are UNSUPPORTED. They are
|
||||
unsupported by the 80486. They are the Pseudo-NaNs, Pseudoinfinities,
|
||||
and Unnormals. None of these will be generated by an 80486 or by the
|
||||
emulator. Do not use them. The emulator treats them differently in
|
||||
detail from the way an 80486 does.
|
||||
|
||||
The emulator treats PseudoDenormals differently from an 80486. These
|
||||
numbers are in fact properly normalised numbers with the exponent
|
||||
offset by 1, and the emulator treats them as such. Unlike the 80486,
|
||||
the emulator does not generate a Denormal Operand exception for these
|
||||
numbers. The arithmetical results produced when using such a number as
|
||||
an operand are the same for the emulator and a real 80486 (apart from
|
||||
any slight precision difference for the transcendental functions).
|
||||
Neither the emulator nor an 80486 produces one of these numbers as the
|
||||
result of any arithmetic operation. An 80486 can keep one of these
|
||||
numbers in an FPU register with its identity as a PseudoDenormal, but
|
||||
the emulator will not; they are always converted to a valid number.
|
||||
|
||||
----------------------- Performance of wm-FPU-emu -----------------------
|
||||
|
||||
Speed.
|
||||
-----
|
||||
|
||||
The speed of floating point computation with the emulator will depend
|
||||
upon instruction mix. Relative performance is best for the instructions
|
||||
which require most computation. The simple instructions are adversely
|
||||
affected by the fpu instruction trap overhead.
|
||||
|
||||
|
||||
Timing: Some simple timing tests have been made on the emulator functions.
|
||||
The times include load/store instructions. All times are in microseconds
|
||||
measured on a 33MHz 386 with 64k cache. The Turbo C tests were under
|
||||
ms-dos, the next two columns are for emulators running with the djgpp
|
||||
ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97,
|
||||
using libm4.0 (hard).
|
||||
|
||||
function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu
|
||||
|
||||
+ 60.5 154.8 76.5 139.4
|
||||
- 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7
|
||||
* 71.0 190.8 79.6 146.6
|
||||
/ 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1
|
||||
|
||||
sin() 310.8 4692.0 319.0 398.5
|
||||
cos() 284.4 4855.2 308.0 388.7
|
||||
tan() 495.0 8807.1 394.9 504.7
|
||||
atan() 328.9 4866.4 601.1 419.5-491.9
|
||||
|
||||
sqrt() 128.7 crashed 145.2 227.0
|
||||
log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1
|
||||
exp() 479.1 6619.2 469.1 850.8
|
||||
|
||||
|
||||
The performance under Linux is improved by the use of look-ahead code.
|
||||
The following results show the improvement which is obtained under
|
||||
Linux due to the look-ahead code. Also given are the times for the
|
||||
original Linux emulator with the 4.1 'soft' lib.
|
||||
|
||||
[ Linus' note: I changed look-ahead to be the default under linux, as
|
||||
there was no reason not to use it after I had edited it to be
|
||||
disabled during tracing ]
|
||||
|
||||
wm-FPU-emu w original w
|
||||
look-ahead 'soft' lib
|
||||
+ 106.4 190.2
|
||||
- 108.6-111.6 192.4-216.2
|
||||
* 113.4 193.1
|
||||
/ 108.8-124.4 700.1-706.2
|
||||
|
||||
sin() 390.5 2642.0
|
||||
cos() 381.5 2767.4
|
||||
tan() 496.5 3153.3
|
||||
atan() 367.2-435.5 2439.4-3396.8
|
||||
|
||||
sqrt() 195.1 4732.5
|
||||
log() 358.0-387.5 3359.2-3390.3
|
||||
exp() 619.3 4046.4
|
||||
|
||||
|
||||
These figures are now somewhat out-of-date. The emulator has become
|
||||
progressively slower for most functions as more of the 80486 features
|
||||
have been implemented.
|
||||
|
||||
|
||||
----------------------- Accuracy of wm-FPU-emu -----------------------
|
||||
|
||||
|
||||
Accuracy: The following table gives the accuracy of the sqrt(), trig
|
||||
and log functions. Each function was tested at about 400 points. Ideal
|
||||
results would be 64 bits. The reduced accuracy of cos() and tan() for
|
||||
arguments greater than pi/4 can be thought of as being due to the
|
||||
precision of the argument x; e.g. an argument of pi/2-(1e-10) which is
|
||||
accurate to 64 bits can result in a relative accuracy in cos() of about
|
||||
64 + log2(cos(x)) = 31 bits. Results for the Turbo C emulator are given
|
||||
in the last column.
|
||||
|
||||
|
||||
Function Tested x range Worst result Turbo C
|
||||
(relative bits)
|
||||
|
||||
sqrt(x) 1 .. 2 64.1 63.2
|
||||
atan(x) 1e-10 .. 200 62.6 62.8
|
||||
cos(x) 0 .. pi/2-(1e-10) 63.2 (x <= pi/4) 62.4
|
||||
35.2 (x = pi/2-(1e-10)) 31.9
|
||||
sin(x) 1e-10 .. pi/2 63.0 62.8
|
||||
tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1
|
||||
35.2 (x = pi/2-(1e-10)) 31.9
|
||||
exp(x) 0 .. 1 63.1 62.9
|
||||
log(x) 1+1e-6 .. 2 62.4 62.1
|
||||
|
||||
|
||||
As of version 1.3 of the emulator, the accuracy of the basic
|
||||
arithmetic has been improved (by a small fraction of a bit). Care has
|
||||
been taken to ensure full accuracy of the rounding of the basic
|
||||
arithmetic functions (+,-,*,/,and fsqrt), and they all now produce
|
||||
results which are exact to the 64th bit (unless there are any bugs
|
||||
left). To ensure this, it was necessary to effectively get information
|
||||
of up to about 128 bits precision. The emulator now passes the
|
||||
"paranoia" tests (compiled with gcc 2.3.3) for 'float' variables (24
|
||||
bit precision numbers) when precision control is set to 24, 53 or 64
|
||||
bits, and for 'double' variables (53 bit precision numbers) when
|
||||
precision control is set to 53 bits (a properly performing FPU cannot
|
||||
pass the 'paranoia' tests for 'double' variables when precision
|
||||
control is set to 64 bits).
|
||||
|
||||
For version 1.5, the accuracy of fprem and fprem1 has been improved.
|
||||
These functions now produce exact results. The code for reducing the
|
||||
argument for the trig functions (fsin, fcos, fptan and fsincos) has
|
||||
been improved and now effectively uses a value for pi which is
|
||||
accurate to more than 128 bits precision. As a consquence, the
|
||||
accuracy of these functions for large arguments has been dramatically
|
||||
improved (and is now very much better than an 80486 FPU). There is
|
||||
also now no degradation of accuracy for fcos and ftan for operands
|
||||
close to pi/2. Measured results are (note that the definition of
|
||||
accuracy has changed slightly from that used for the above table):
|
||||
|
||||
Function Tested x range Worst result
|
||||
(absolute bits)
|
||||
|
||||
cos(x) 0 .. 9.22e+18 62.0
|
||||
sin(x) 1e-16 .. 9.22e+18 62.1
|
||||
tan(x) 1e-16 .. 9.22e+18 61.8
|
||||
|
||||
It is possible with some effort to find very large arguments which
|
||||
give much degraded precision. For example, the integer number
|
||||
8227740058411162616.0
|
||||
is within about 10e-7 of a multiple of pi. To find the tan (for
|
||||
example) of this number to 64 bits precision it would be necessary to
|
||||
have a value of pi which had about 150 bits precision. The FPU
|
||||
emulator computes the result to about 42.6 bits precision (the correct
|
||||
result is about -9.739715e-8). On the other hand, an 80486 FPU returns
|
||||
0.01059, which in relative terms is hopelessly inaccurate.
|
||||
|
||||
For arguments close to critical angles (which occur at multiples of
|
||||
pi/2) the emulator is more accurate than an 80486 FPU. For very large
|
||||
arguments, the emulator is far more accurate.
|
||||
|
||||
------------------------- Contributors -------------------------------
|
||||
|
||||
A number of people have contributed to the development of the
|
||||
emulator, often by just reporting bugs, sometimes with suggested
|
||||
fixes, and a few kind people have provided me with access in one way
|
||||
or another to an 80486 machine. Contributors include (to those people
|
||||
who I may have forgotten, please forgive me):
|
||||
|
||||
Linus Torvalds
|
||||
Tommy.Thorn@daimi.aau.dk
|
||||
Andrew.Tridgell@anu.edu.au
|
||||
Nick Holloway, alfie@dcs.warwick.ac.uk
|
||||
Hermano Moura, moura@dcs.gla.ac.uk
|
||||
Jon Jagger, J.Jagger@scp.ac.uk
|
||||
Lennart Benschop
|
||||
Brian Gallew, geek+@CMU.EDU
|
||||
Thomas Staniszewski, ts3v+@andrew.cmu.edu
|
||||
Martin Howell, mph@plasma.apana.org.au
|
||||
M Saggaf, alsaggaf@athena.mit.edu
|
||||
Peter Barker, PETER@socpsy.sci.fau.edu
|
||||
tom@vlsivie.tuwien.ac.at
|
||||
Dan Russel, russed@rpi.edu
|
||||
Daniel Carosone, danielce@ee.mu.oz.au
|
||||
cae@jpmorgan.com
|
||||
Hamish Coleman, t933093@minyos.xx.rmit.oz.au
|
||||
Bruce Evans, bde@kralizec.zeta.org.au
|
||||
Timo Korvola, Timo.Korvola@hut.fi
|
||||
|
||||
...and numerous others who responded to my request for help with
|
||||
a real 80486.
|
||||
|
44
source/THIRDPARTY/linux-old/drivers/FPU-emu/control_w.h
Normal file
44
source/THIRDPARTY/linux-old/drivers/FPU-emu/control_w.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| control_w.h |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _CONTROLW_H_
|
||||
#define _CONTROLW_H_
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#define _Const_(x) $##x
|
||||
#else
|
||||
#define _Const_(x) x
|
||||
#endif
|
||||
|
||||
#define CW_RC _Const_(0x0C00) /* rounding control */
|
||||
#define CW_PC _Const_(0x0300) /* precision control */
|
||||
|
||||
#define CW_Precision Const_(0x0020) /* loss of precision mask */
|
||||
#define CW_Underflow Const_(0x0010) /* underflow mask */
|
||||
#define CW_Overflow Const_(0x0008) /* overflow mask */
|
||||
#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */
|
||||
#define CW_Denormal Const_(0x0002) /* denormalized operand mask */
|
||||
#define CW_Invalid Const_(0x0001) /* invalid operation mask */
|
||||
|
||||
#define CW_Exceptions _Const_(0x003f) /* all masks */
|
||||
|
||||
#define RC_RND _Const_(0x0000)
|
||||
#define RC_DOWN _Const_(0x0400)
|
||||
#define RC_UP _Const_(0x0800)
|
||||
#define RC_CHOP _Const_(0x0C00)
|
||||
|
||||
/* p 15-5: Precision control bits affect only the following:
|
||||
ADD, SUB(R), MUL, DIV(R), and SQRT */
|
||||
#define PR_24_BITS _Const_(0x000)
|
||||
#define PR_53_BITS _Const_(0x200)
|
||||
#define PR_64_BITS _Const_(0x300)
|
||||
/* FULL_PRECISION simulates all exceptions masked */
|
||||
#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f)
|
||||
|
||||
#endif _CONTROLW_H_
|
50
source/THIRDPARTY/linux-old/drivers/FPU-emu/div_small.S
Normal file
50
source/THIRDPARTY/linux-old/drivers/FPU-emu/div_small.S
Normal file
|
@ -0,0 +1,50 @@
|
|||
.file "div_small.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| div_small.S |
|
||||
| |
|
||||
| Divide a 64 bit integer by a 32 bit integer & return remainder. |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| unsigned long div_small(unsigned long long *x, unsigned long y) |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_asm.h"
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
|
||||
.globl _div_small
|
||||
|
||||
_div_small:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
|
||||
pushl %esi
|
||||
|
||||
movl PARAM1,%esi /* pointer to num */
|
||||
movl PARAM2,%ecx /* The denominator */
|
||||
|
||||
movl 4(%esi),%eax /* Get the current num msw */
|
||||
xorl %edx,%edx
|
||||
divl %ecx
|
||||
|
||||
movl %eax,4(%esi)
|
||||
|
||||
movl (%esi),%eax /* Get the num lsw */
|
||||
divl %ecx
|
||||
|
||||
movl %eax,(%esi)
|
||||
|
||||
movl %edx,%eax /* Return the remainder in eax */
|
||||
|
||||
popl %esi
|
||||
|
||||
leave
|
||||
ret
|
||||
|
628
source/THIRDPARTY/linux-old/drivers/FPU-emu/errors.c
Normal file
628
source/THIRDPARTY/linux-old/drivers/FPU-emu/errors.c
Normal file
|
@ -0,0 +1,628 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| errors.c |
|
||||
| |
|
||||
| The error handling functions for wm-FPU-emu |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Note: |
|
||||
| The file contains code which accesses user memory. |
|
||||
| Emulator static data may change when user memory is accessed, due to |
|
||||
| other processes using the emulator while swapping is in progress. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "status_w.h"
|
||||
#include "control_w.h"
|
||||
#include "reg_constant.h"
|
||||
#include "version.h"
|
||||
|
||||
/* */
|
||||
#undef PRINT_MESSAGES
|
||||
/* */
|
||||
|
||||
|
||||
void Un_impl(void)
|
||||
{
|
||||
unsigned char byte1, FPU_modrm;
|
||||
unsigned long address = FPU_ORIG_EIP;
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
/* No need to verify_area(), we have previously fetched these bytes. */
|
||||
printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
|
||||
while ( 1 )
|
||||
{
|
||||
byte1 = get_fs_byte((unsigned char *) address);
|
||||
if ( (byte1 & 0xf8) == 0xd8 ) break;
|
||||
printk("[%02x]", byte1);
|
||||
address++;
|
||||
}
|
||||
printk("%02x ", byte1);
|
||||
FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
|
||||
|
||||
if (FPU_modrm >= 0300)
|
||||
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
|
||||
else
|
||||
printk("/%d\n", (FPU_modrm >> 3) & 7);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
|
||||
EXCEPTION(EX_Invalid);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Called for opcodes which are illegal and which are known to result in a
|
||||
SIGILL with a real 80486.
|
||||
*/
|
||||
void FPU_illegal(void)
|
||||
{
|
||||
math_abort(FPU_info,SIGILL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void emu_printall()
|
||||
{
|
||||
int i;
|
||||
static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
|
||||
"DeNorm", "Inf", "NaN", "Empty" };
|
||||
unsigned char byte1, FPU_modrm;
|
||||
unsigned long address = FPU_ORIG_EIP;
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
/* No need to verify_area(), we have previously fetched these bytes. */
|
||||
printk("At %p: ", (void *) address);
|
||||
while ( 1 )
|
||||
{
|
||||
byte1 = get_fs_byte((unsigned char *) address);
|
||||
if ( (byte1 & 0xf8) == 0xd8 ) break;
|
||||
printk("[%02x]", byte1);
|
||||
address++;
|
||||
}
|
||||
printk("%02x ", byte1);
|
||||
FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
|
||||
partial_status = status_word();
|
||||
|
||||
#ifdef DEBUGGING
|
||||
if ( partial_status & SW_Backward ) printk("SW: backward compatibility\n");
|
||||
if ( partial_status & SW_C3 ) printk("SW: condition bit 3\n");
|
||||
if ( partial_status & SW_C2 ) printk("SW: condition bit 2\n");
|
||||
if ( partial_status & SW_C1 ) printk("SW: condition bit 1\n");
|
||||
if ( partial_status & SW_C0 ) printk("SW: condition bit 0\n");
|
||||
if ( partial_status & SW_Summary ) printk("SW: exception summary\n");
|
||||
if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n");
|
||||
if ( partial_status & SW_Precision ) printk("SW: loss of precision\n");
|
||||
if ( partial_status & SW_Underflow ) printk("SW: underflow\n");
|
||||
if ( partial_status & SW_Overflow ) printk("SW: overflow\n");
|
||||
if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n");
|
||||
if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n");
|
||||
if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n");
|
||||
#endif DEBUGGING
|
||||
|
||||
if (FPU_modrm >= 0300)
|
||||
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
|
||||
else
|
||||
printk("/%d, mod=%d rm=%d\n",
|
||||
(FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
|
||||
|
||||
printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
|
||||
partial_status & 0x8000 ? 1 : 0, /* busy */
|
||||
(partial_status & 0x3800) >> 11, /* stack top pointer */
|
||||
partial_status & 0x80 ? 1 : 0, /* Error summary status */
|
||||
partial_status & 0x40 ? 1 : 0, /* Stack flag */
|
||||
partial_status & SW_C3?1:0, partial_status & SW_C2?1:0, /* cc */
|
||||
partial_status & SW_C1?1:0, partial_status & SW_C0?1:0, /* cc */
|
||||
partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0,
|
||||
partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0,
|
||||
partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0);
|
||||
|
||||
printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
|
||||
control_word & 0x1000 ? 1 : 0,
|
||||
(control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
|
||||
(control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
|
||||
control_word & 0x80 ? 1 : 0,
|
||||
control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0,
|
||||
control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0,
|
||||
control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0);
|
||||
|
||||
for ( i = 0; i < 8; i++ )
|
||||
{
|
||||
FPU_REG *r = &st(i);
|
||||
switch (r->tag)
|
||||
{
|
||||
case TW_Empty:
|
||||
continue;
|
||||
break;
|
||||
case TW_Zero:
|
||||
#if 0
|
||||
printk("st(%d) %c .0000 0000 0000 0000 ",
|
||||
i, r->sign ? '-' : '+');
|
||||
break;
|
||||
#endif
|
||||
case TW_Valid:
|
||||
case TW_NaN:
|
||||
/* case TW_Denormal: */
|
||||
case TW_Infinity:
|
||||
printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
|
||||
r->sign ? '-' : '+',
|
||||
(long)(r->sigh >> 16),
|
||||
(long)(r->sigh & 0xFFFF),
|
||||
(long)(r->sigl >> 16),
|
||||
(long)(r->sigl & 0xFFFF),
|
||||
r->exp - EXP_BIAS + 1);
|
||||
break;
|
||||
default:
|
||||
printk("Whoops! Error in errors.c ");
|
||||
break;
|
||||
}
|
||||
printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
|
||||
}
|
||||
|
||||
printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
|
||||
FPU_loaded_data.sign ? '-' : '+',
|
||||
(long)(FPU_loaded_data.sigh >> 16),
|
||||
(long)(FPU_loaded_data.sigh & 0xFFFF),
|
||||
(long)(FPU_loaded_data.sigl >> 16),
|
||||
(long)(FPU_loaded_data.sigl & 0xFFFF),
|
||||
FPU_loaded_data.exp - EXP_BIAS + 1);
|
||||
printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
|
||||
}
|
||||
|
||||
static struct {
|
||||
int type;
|
||||
char *name;
|
||||
} exception_names[] = {
|
||||
{ EX_StackOver, "stack overflow" },
|
||||
{ EX_StackUnder, "stack underflow" },
|
||||
{ EX_Precision, "loss of precision" },
|
||||
{ EX_Underflow, "underflow" },
|
||||
{ EX_Overflow, "overflow" },
|
||||
{ EX_ZeroDiv, "divide by zero" },
|
||||
{ EX_Denormal, "denormalized operand" },
|
||||
{ EX_Invalid, "invalid operation" },
|
||||
{ EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
EX_INTERNAL is always given with a code which indicates where the
|
||||
error was detected.
|
||||
|
||||
Internal error types:
|
||||
0 in load_store.c
|
||||
0x14 in fpu_etc.c
|
||||
0x1nn in a *.c file:
|
||||
0x101 in reg_add_sub.c
|
||||
0x102 in reg_mul.c
|
||||
0x103 in poly_sin.c
|
||||
0x104 in poly_atan.c
|
||||
0x105 in reg_mul.c
|
||||
0x106 in reg_ld_str.c
|
||||
0x107 in fpu_trig.c
|
||||
0x108 in reg_compare.c
|
||||
0x109 in reg_compare.c
|
||||
0x110 in reg_add_sub.c
|
||||
0x111 in fpe_entry.c
|
||||
0x112 in fpu_trig.c
|
||||
0x113 in errors.c
|
||||
0x114 in reg_ld_str.c
|
||||
0x115 in fpu_trig.c
|
||||
0x116 in fpu_trig.c
|
||||
0x117 in fpu_trig.c
|
||||
0x118 in fpu_trig.c
|
||||
0x119 in fpu_trig.c
|
||||
0x120 in poly_atan.c
|
||||
0x121 in reg_compare.c
|
||||
0x122 in reg_compare.c
|
||||
0x123 in reg_compare.c
|
||||
0x125 in fpu_trig.c
|
||||
0x126 in fpu_entry.c
|
||||
0x127 in poly_2xm1.c
|
||||
0x128 in fpu_entry.c
|
||||
0x2nn in an *.S file:
|
||||
0x201 in reg_u_add.S, reg_round.S
|
||||
0x202 in reg_u_div.S
|
||||
0x203 in reg_u_div.S
|
||||
0x204 in reg_u_div.S
|
||||
0x205 in reg_u_mul.S
|
||||
0x206 in reg_u_sub.S
|
||||
0x207 in wm_sqrt.S
|
||||
0x208 in reg_div.S
|
||||
0x209 in reg_u_sub.S
|
||||
0x210 in reg_u_sub.S
|
||||
0x211 in reg_u_sub.S
|
||||
0x212 in reg_u_sub.S
|
||||
0x213 in wm_sqrt.S
|
||||
0x214 in wm_sqrt.S
|
||||
0x215 in wm_sqrt.S
|
||||
0x216 in reg_round.S
|
||||
0x217 in reg_round.S
|
||||
0x218 in reg_round.S
|
||||
0x220 in reg_norm.S
|
||||
0x221 in reg_norm.S
|
||||
*/
|
||||
|
||||
void exception(int n)
|
||||
{
|
||||
int i, int_type;
|
||||
|
||||
int_type = 0; /* Needed only to stop compiler warnings */
|
||||
if ( n & EX_INTERNAL )
|
||||
{
|
||||
int_type = n - EX_INTERNAL;
|
||||
n = EX_INTERNAL;
|
||||
/* Set lots of exception bits! */
|
||||
partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Extract only the bits which we use to set the status word */
|
||||
n &= (SW_Exc_Mask);
|
||||
/* Set the corresponding exception bit */
|
||||
partial_status |= n;
|
||||
/* Set summary bits iff exception isn't masked */
|
||||
if ( partial_status & ~control_word & CW_Exceptions )
|
||||
partial_status |= (SW_Summary | SW_Backward);
|
||||
if ( n & (SW_Stack_Fault | EX_Precision) )
|
||||
{
|
||||
if ( !(n & SW_C1) )
|
||||
/* This bit distinguishes over- from underflow for a stack fault,
|
||||
and roundup from round-down for precision loss. */
|
||||
partial_status &= ~SW_C1;
|
||||
}
|
||||
}
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
|
||||
{
|
||||
#ifdef PRINT_MESSAGES
|
||||
/* My message from the sponsor */
|
||||
printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
|
||||
#endif PRINT_MESSAGES
|
||||
|
||||
/* Get a name string for error reporting */
|
||||
for (i=0; exception_names[i].type; i++)
|
||||
if ( (exception_names[i].type & n) == exception_names[i].type )
|
||||
break;
|
||||
|
||||
if (exception_names[i].type)
|
||||
{
|
||||
#ifdef PRINT_MESSAGES
|
||||
printk("FP Exception: %s!\n", exception_names[i].name);
|
||||
#endif PRINT_MESSAGES
|
||||
}
|
||||
else
|
||||
printk("FP emulator: Unknown Exception: 0x%04x!\n", n);
|
||||
|
||||
if ( n == EX_INTERNAL )
|
||||
{
|
||||
printk("FP emulator: Internal error type 0x%04x\n", int_type);
|
||||
emu_printall();
|
||||
}
|
||||
#ifdef PRINT_MESSAGES
|
||||
else
|
||||
emu_printall();
|
||||
#endif PRINT_MESSAGES
|
||||
|
||||
/*
|
||||
* The 80486 generates an interrupt on the next non-control FPU
|
||||
* instruction. So we need some means of flagging it.
|
||||
* We use the ES (Error Summary) bit for this, assuming that
|
||||
* this is the way a real FPU does it (until I can check it out),
|
||||
* if not, then some method such as the following kludge might
|
||||
* be needed.
|
||||
*/
|
||||
/* regs[0].tag |= TW_FPU_Interrupt; */
|
||||
}
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
|
||||
#ifdef __DEBUG__
|
||||
math_abort(FPU_info,SIGFPE);
|
||||
#endif __DEBUG__
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Real operation attempted on two operands, one a NaN. */
|
||||
/* Returns nz if the exception is unmasked */
|
||||
asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
|
||||
{
|
||||
FPU_REG const *x;
|
||||
int signalling;
|
||||
|
||||
/* The default result for the case of two "equal" NaNs (signs may
|
||||
differ) is chosen to reproduce 80486 behaviour */
|
||||
x = a;
|
||||
if (a->tag == TW_NaN)
|
||||
{
|
||||
if (b->tag == TW_NaN)
|
||||
{
|
||||
signalling = !(a->sigh & b->sigh & 0x40000000);
|
||||
/* find the "larger" */
|
||||
if ( significand(a) < significand(b) )
|
||||
x = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* return the quiet version of the NaN in a */
|
||||
signalling = !(a->sigh & 0x40000000);
|
||||
}
|
||||
}
|
||||
else
|
||||
#ifdef PARANOID
|
||||
if (b->tag == TW_NaN)
|
||||
#endif PARANOID
|
||||
{
|
||||
signalling = !(b->sigh & 0x40000000);
|
||||
x = b;
|
||||
}
|
||||
#ifdef PARANOID
|
||||
else
|
||||
{
|
||||
signalling = 0;
|
||||
EXCEPTION(EX_INTERNAL|0x113);
|
||||
x = &CONST_QNaN;
|
||||
}
|
||||
#endif PARANOID
|
||||
|
||||
if ( !signalling )
|
||||
{
|
||||
if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
|
||||
x = &CONST_QNaN;
|
||||
reg_move(x, dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( control_word & CW_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
|
||||
x = &CONST_QNaN;
|
||||
reg_move(x, dest);
|
||||
/* ensure a Quiet NaN */
|
||||
dest->sigh |= 0x40000000;
|
||||
}
|
||||
|
||||
EXCEPTION(EX_Invalid);
|
||||
|
||||
return !(control_word & CW_Invalid);
|
||||
}
|
||||
|
||||
|
||||
/* Invalid arith operation on Valid registers */
|
||||
/* Returns nz if the exception is unmasked */
|
||||
asmlinkage int arith_invalid(FPU_REG *dest)
|
||||
{
|
||||
|
||||
EXCEPTION(EX_Invalid);
|
||||
|
||||
if ( control_word & CW_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
reg_move(&CONST_QNaN, dest);
|
||||
}
|
||||
|
||||
return !(control_word & CW_Invalid);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Divide a finite number by zero */
|
||||
asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
|
||||
{
|
||||
|
||||
if ( control_word & CW_ZeroDiv )
|
||||
{
|
||||
/* The masked response */
|
||||
reg_move(&CONST_INF, dest);
|
||||
dest->sign = (unsigned char)sign;
|
||||
}
|
||||
|
||||
EXCEPTION(EX_ZeroDiv);
|
||||
|
||||
return !(control_word & CW_ZeroDiv);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This may be called often, so keep it lean */
|
||||
int set_precision_flag(int flags)
|
||||
{
|
||||
if ( control_word & CW_Precision )
|
||||
{
|
||||
partial_status &= ~(SW_C1 & flags);
|
||||
partial_status |= flags; /* The masked response */
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
exception(flags);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This may be called often, so keep it lean */
|
||||
asmlinkage void set_precision_flag_up(void)
|
||||
{
|
||||
if ( control_word & CW_Precision )
|
||||
partial_status |= (SW_Precision | SW_C1); /* The masked response */
|
||||
else
|
||||
exception(EX_Precision | SW_C1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This may be called often, so keep it lean */
|
||||
asmlinkage void set_precision_flag_down(void)
|
||||
{
|
||||
if ( control_word & CW_Precision )
|
||||
{ /* The masked response */
|
||||
partial_status &= ~SW_C1;
|
||||
partial_status |= SW_Precision;
|
||||
}
|
||||
else
|
||||
exception(EX_Precision);
|
||||
}
|
||||
|
||||
|
||||
asmlinkage int denormal_operand(void)
|
||||
{
|
||||
if ( control_word & CW_Denormal )
|
||||
{ /* The masked response */
|
||||
partial_status |= SW_Denorm_Op;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
exception(EX_Denormal);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
asmlinkage int arith_overflow(FPU_REG *dest)
|
||||
{
|
||||
|
||||
if ( control_word & CW_Overflow )
|
||||
{
|
||||
char sign;
|
||||
/* The masked response */
|
||||
/* ###### The response here depends upon the rounding mode */
|
||||
sign = dest->sign;
|
||||
reg_move(&CONST_INF, dest);
|
||||
dest->sign = sign;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Subtract the magic number from the exponent */
|
||||
dest->exp -= (3 * (1 << 13));
|
||||
}
|
||||
|
||||
EXCEPTION(EX_Overflow);
|
||||
if ( control_word & CW_Overflow )
|
||||
{
|
||||
/* The overflow exception is masked. */
|
||||
/* By definition, precision is lost.
|
||||
The roundup bit (C1) is also set because we have
|
||||
"rounded" upwards to Infinity. */
|
||||
EXCEPTION(EX_Precision | SW_C1);
|
||||
return !(control_word & CW_Precision);
|
||||
}
|
||||
|
||||
return !(control_word & CW_Overflow);
|
||||
|
||||
}
|
||||
|
||||
|
||||
asmlinkage int arith_underflow(FPU_REG *dest)
|
||||
{
|
||||
|
||||
if ( control_word & CW_Underflow )
|
||||
{
|
||||
/* The masked response */
|
||||
if ( dest->exp <= EXP_UNDER - 63 )
|
||||
{
|
||||
reg_move(&CONST_Z, dest);
|
||||
partial_status &= ~SW_C1; /* Round down. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add the magic number to the exponent. */
|
||||
dest->exp += (3 * (1 << 13));
|
||||
}
|
||||
|
||||
EXCEPTION(EX_Underflow);
|
||||
if ( control_word & CW_Underflow )
|
||||
{
|
||||
/* The underflow exception is masked. */
|
||||
EXCEPTION(EX_Precision);
|
||||
return !(control_word & CW_Precision);
|
||||
}
|
||||
|
||||
return !(control_word & CW_Underflow);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void stack_overflow(void)
|
||||
{
|
||||
|
||||
if ( control_word & CW_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
top--;
|
||||
reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
|
||||
}
|
||||
|
||||
EXCEPTION(EX_StackOver);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void stack_underflow(void)
|
||||
{
|
||||
|
||||
if ( control_word & CW_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
reg_move(&CONST_QNaN, FPU_st0_ptr);
|
||||
}
|
||||
|
||||
EXCEPTION(EX_StackUnder);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void stack_underflow_i(int i)
|
||||
{
|
||||
|
||||
if ( control_word & CW_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
reg_move(&CONST_QNaN, &(st(i)));
|
||||
}
|
||||
|
||||
EXCEPTION(EX_StackUnder);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void stack_underflow_pop(int i)
|
||||
{
|
||||
|
||||
if ( control_word & CW_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
reg_move(&CONST_QNaN, &(st(i)));
|
||||
pop();
|
||||
}
|
||||
|
||||
EXCEPTION(EX_StackUnder);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
53
source/THIRDPARTY/linux-old/drivers/FPU-emu/exception.h
Normal file
53
source/THIRDPARTY/linux-old/drivers/FPU-emu/exception.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| exception.h |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _EXCEPTION_H_
|
||||
#define _EXCEPTION_H_
|
||||
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#define Const_(x) $##x
|
||||
#else
|
||||
#define Const_(x) x
|
||||
#endif
|
||||
|
||||
#ifndef SW_C1
|
||||
#include "fpu_emu.h"
|
||||
#endif SW_C1
|
||||
|
||||
#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
|
||||
#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
|
||||
/* Special exceptions: */
|
||||
#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
|
||||
#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
|
||||
#define EX_StackUnder Const_(0x0041) /* stack underflow */
|
||||
/* Exception flags: */
|
||||
#define EX_Precision Const_(0x0020) /* loss of precision */
|
||||
#define EX_Underflow Const_(0x0010) /* underflow */
|
||||
#define EX_Overflow Const_(0x0008) /* overflow */
|
||||
#define EX_ZeroDiv Const_(0x0004) /* divide by zero */
|
||||
#define EX_Denormal Const_(0x0002) /* denormalized operand */
|
||||
#define EX_Invalid Const_(0x0001) /* invalid operation */
|
||||
|
||||
|
||||
#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1))
|
||||
#define PRECISION_LOST_DOWN Const_(EX_Precision)
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#ifdef DEBUG
|
||||
#define EXCEPTION(x) { printk("exception in %s at line %d\n", \
|
||||
__FILE__, __LINE__); exception(x); }
|
||||
#else
|
||||
#define EXCEPTION(x) exception(x)
|
||||
#endif
|
||||
|
||||
#endif __ASSEMBLER__
|
||||
|
||||
#endif _EXCEPTION_H_
|
179
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_arith.c
Normal file
179
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_arith.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_arith.c |
|
||||
| |
|
||||
| Code to implement the FPU register/register arithmetic instructions |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
#include "status_w.h"
|
||||
|
||||
|
||||
void fadd__()
|
||||
{
|
||||
/* fadd st,st(i) */
|
||||
clear_C1();
|
||||
reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
|
||||
}
|
||||
|
||||
|
||||
void fmul__()
|
||||
{
|
||||
/* fmul st,st(i) */
|
||||
clear_C1();
|
||||
reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fsub__()
|
||||
{
|
||||
/* fsub st,st(i) */
|
||||
clear_C1();
|
||||
reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
|
||||
}
|
||||
|
||||
|
||||
void fsubr_()
|
||||
{
|
||||
/* fsubr st,st(i) */
|
||||
clear_C1();
|
||||
reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
|
||||
}
|
||||
|
||||
|
||||
void fdiv__()
|
||||
{
|
||||
/* fdiv st,st(i) */
|
||||
clear_C1();
|
||||
reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
|
||||
}
|
||||
|
||||
|
||||
void fdivr_()
|
||||
{
|
||||
/* fdivr st,st(i) */
|
||||
clear_C1();
|
||||
reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fadd_i()
|
||||
{
|
||||
/* fadd st(i),st */
|
||||
clear_C1();
|
||||
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
|
||||
}
|
||||
|
||||
|
||||
void fmul_i()
|
||||
{
|
||||
/* fmul st(i),st */
|
||||
clear_C1();
|
||||
reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
|
||||
}
|
||||
|
||||
|
||||
void fsubri()
|
||||
{
|
||||
/* fsubr st(i),st */
|
||||
/* This is the sense of the 80486 manual
|
||||
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
|
||||
clear_C1();
|
||||
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
|
||||
}
|
||||
|
||||
|
||||
void fsub_i()
|
||||
{
|
||||
/* fsub st(i),st */
|
||||
/* This is the sense of the 80486 manual
|
||||
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
|
||||
clear_C1();
|
||||
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
|
||||
}
|
||||
|
||||
|
||||
void fdivri()
|
||||
{
|
||||
/* fdivr st(i),st */
|
||||
clear_C1();
|
||||
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
|
||||
}
|
||||
|
||||
|
||||
void fdiv_i()
|
||||
{
|
||||
/* fdiv st(i),st */
|
||||
clear_C1();
|
||||
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void faddp_()
|
||||
{
|
||||
/* faddp st(i),st */
|
||||
clear_C1();
|
||||
if ( !reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fmulp_()
|
||||
{
|
||||
/* fmulp st(i),st */
|
||||
clear_C1();
|
||||
if ( !reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fsubrp()
|
||||
{
|
||||
/* fsubrp st(i),st */
|
||||
/* This is the sense of the 80486 manual
|
||||
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
|
||||
clear_C1();
|
||||
if ( !reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fsubp_()
|
||||
{
|
||||
/* fsubp st(i),st */
|
||||
/* This is the sense of the 80486 manual
|
||||
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
|
||||
clear_C1();
|
||||
if ( !reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fdivrp()
|
||||
{
|
||||
/* fdivrp st(i),st */
|
||||
clear_C1();
|
||||
if ( !reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fdivp_()
|
||||
{
|
||||
/* fdivp st(i),st */
|
||||
clear_C1();
|
||||
if ( !reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
|
||||
pop();
|
||||
}
|
||||
|
30
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_asm.h
Normal file
30
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_asm.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_asm.h |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _FPU_ASM_H_
|
||||
#define _FPU_ASM_H_
|
||||
|
||||
#include "fpu_emu.h"
|
||||
|
||||
#define EXCEPTION _exception
|
||||
|
||||
|
||||
#define PARAM1 8(%ebp)
|
||||
#define PARAM2 12(%ebp)
|
||||
#define PARAM3 16(%ebp)
|
||||
#define PARAM4 20(%ebp)
|
||||
|
||||
#define SIGL_OFFSET 8
|
||||
#define SIGN(x) (x)
|
||||
#define TAG(x) 1(x)
|
||||
#define EXP(x) 4(x)
|
||||
#define SIG(x) SIGL_OFFSET##(x)
|
||||
#define SIGL(x) SIGL_OFFSET##(x)
|
||||
#define SIGH(x) 12(x)
|
||||
|
||||
#endif _FPU_ASM_H_
|
180
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_aux.c
Normal file
180
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_aux.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_aux.c |
|
||||
| |
|
||||
| Code to implement some of the FPU auxiliary instructions. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "status_w.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
|
||||
void fclex(void)
|
||||
{
|
||||
partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
|
||||
SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
|
||||
SW_Invalid);
|
||||
NO_NET_DATA_EFFECT;
|
||||
FPU_entry_eip = ip_offset; /* We want no net effect */
|
||||
}
|
||||
|
||||
/* Needs to be externally visible */
|
||||
void finit()
|
||||
{
|
||||
int r;
|
||||
control_word = 0x037f;
|
||||
partial_status = 0;
|
||||
top = 0; /* We don't keep top in the status word internally. */
|
||||
for (r = 0; r < 8; r++)
|
||||
{
|
||||
regs[r].tag = TW_Empty;
|
||||
}
|
||||
/* The behaviour is different to that detailed in
|
||||
Section 15.1.6 of the Intel manual */
|
||||
data_operand_offset = 0;
|
||||
operand_selector = 0;
|
||||
NO_NET_DATA_EFFECT;
|
||||
FPU_entry_op_cs = 0;
|
||||
FPU_entry_eip = ip_offset = 0;
|
||||
}
|
||||
|
||||
static FUNC const finit_table[] = {
|
||||
Un_impl, Un_impl, fclex, finit,
|
||||
Un_impl, FPU_illegal, FPU_illegal, FPU_illegal
|
||||
};
|
||||
|
||||
void finit_()
|
||||
{
|
||||
(finit_table[FPU_rm])();
|
||||
}
|
||||
|
||||
|
||||
static void fstsw_ax(void)
|
||||
{
|
||||
*(short *) &FPU_EAX = status_word();
|
||||
NO_NET_INSTR_EFFECT;
|
||||
}
|
||||
|
||||
static FUNC const fstsw_table[] = {
|
||||
fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
|
||||
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
|
||||
};
|
||||
|
||||
void fstsw_()
|
||||
{
|
||||
(fstsw_table[FPU_rm])();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fnop(void)
|
||||
{
|
||||
}
|
||||
|
||||
static FUNC const fp_nop_table[] = {
|
||||
fnop, FPU_illegal, FPU_illegal, FPU_illegal,
|
||||
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
|
||||
};
|
||||
|
||||
void fp_nop()
|
||||
{
|
||||
(fp_nop_table[FPU_rm])();
|
||||
}
|
||||
|
||||
|
||||
void fld_i_()
|
||||
{
|
||||
FPU_REG *st_new_ptr;
|
||||
|
||||
if ( STACK_OVERFLOW )
|
||||
{ stack_overflow(); return; }
|
||||
|
||||
/* fld st(i) */
|
||||
if ( NOT_EMPTY(FPU_rm) )
|
||||
{ reg_move(&st(FPU_rm), st_new_ptr); push(); }
|
||||
else
|
||||
{
|
||||
if ( control_word & EX_Invalid )
|
||||
{
|
||||
/* The masked response */
|
||||
push();
|
||||
stack_underflow();
|
||||
}
|
||||
else
|
||||
EXCEPTION(EX_StackUnder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fxch_i()
|
||||
{
|
||||
/* fxch st(i) */
|
||||
FPU_REG t;
|
||||
register FPU_REG *sti_ptr = &st(FPU_rm);
|
||||
|
||||
if ( FPU_st0_tag == TW_Empty )
|
||||
{
|
||||
if ( sti_ptr->tag == TW_Empty )
|
||||
{
|
||||
stack_underflow();
|
||||
stack_underflow_i(FPU_rm);
|
||||
return;
|
||||
}
|
||||
if ( control_word & CW_Invalid )
|
||||
reg_move(sti_ptr, FPU_st0_ptr); /* Masked response */
|
||||
stack_underflow_i(FPU_rm);
|
||||
return;
|
||||
}
|
||||
if ( sti_ptr->tag == TW_Empty )
|
||||
{
|
||||
if ( control_word & CW_Invalid )
|
||||
reg_move(FPU_st0_ptr, sti_ptr); /* Masked response */
|
||||
stack_underflow();
|
||||
return;
|
||||
}
|
||||
clear_C1();
|
||||
reg_move(FPU_st0_ptr, &t);
|
||||
reg_move(sti_ptr, FPU_st0_ptr);
|
||||
reg_move(&t, sti_ptr);
|
||||
}
|
||||
|
||||
|
||||
void ffree_()
|
||||
{
|
||||
/* ffree st(i) */
|
||||
st(FPU_rm).tag = TW_Empty;
|
||||
}
|
||||
|
||||
|
||||
void ffreep()
|
||||
{
|
||||
/* ffree st(i) + pop - unofficial code */
|
||||
st(FPU_rm).tag = TW_Empty;
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fst_i_()
|
||||
{
|
||||
/* fst st(i) */
|
||||
reg_move(FPU_st0_ptr, &st(FPU_rm));
|
||||
}
|
||||
|
||||
|
||||
void fstp_i()
|
||||
{
|
||||
/* fstp st(i) */
|
||||
reg_move(FPU_st0_ptr, &st(FPU_rm));
|
||||
pop();
|
||||
}
|
||||
|
166
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_emu.h
Normal file
166
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_emu.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_emu.h |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef _FPU_EMU_H_
|
||||
#define _FPU_EMU_H_
|
||||
|
||||
/*
|
||||
* Define DENORM_OPERAND to make the emulator detect denormals
|
||||
* and use the denormal flag of the status word. Note: this only
|
||||
* affects the flag and corresponding interrupt, the emulator
|
||||
* will always generate denormals and operate upon them as required.
|
||||
*/
|
||||
#define DENORM_OPERAND
|
||||
|
||||
/*
|
||||
* Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
|
||||
* rather than behaviour which appears to be cleaner.
|
||||
* This is a matter of opinion: for all I know, the 80486 may simply
|
||||
* be complying with the IEEE spec. Maybe one day I'll get to see the
|
||||
* spec...
|
||||
*/
|
||||
#define PECULIAR_486
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#include "fpu_asm.h"
|
||||
#define Const(x) $##x
|
||||
#else
|
||||
#define Const(x) x
|
||||
#endif
|
||||
|
||||
#define EXP_BIAS Const(0)
|
||||
#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
|
||||
#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
|
||||
#define EXP_Infinity EXP_OVER
|
||||
#define EXP_NaN EXP_OVER
|
||||
|
||||
#define SIGN_POS Const(0)
|
||||
#define SIGN_NEG Const(1)
|
||||
|
||||
/* Keep the order TW_Valid, TW_Zero, TW_Denormal */
|
||||
#define TW_Valid Const(0) /* valid */
|
||||
#define TW_Zero Const(1) /* zero */
|
||||
/* The following fold to 2 (Special) in the Tag Word */
|
||||
/* #define TW_Denormal Const(4) */ /* De-normal */
|
||||
#define TW_Infinity Const(5) /* + or - infinity */
|
||||
#define TW_NaN Const(6) /* Not a Number */
|
||||
|
||||
#define TW_Empty Const(7) /* empty */
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#ifdef PARANOID
|
||||
extern char emulating;
|
||||
# define RE_ENTRANT_CHECK_OFF emulating = 0
|
||||
# define RE_ENTRANT_CHECK_ON emulating = 1
|
||||
#else
|
||||
# define RE_ENTRANT_CHECK_OFF
|
||||
# define RE_ENTRANT_CHECK_ON
|
||||
#endif PARANOID
|
||||
|
||||
#define FWAIT_OPCODE 0x9b
|
||||
#define OP_SIZE_PREFIX 0x66
|
||||
#define ADDR_SIZE_PREFIX 0x67
|
||||
#define PREFIX_CS 0x2e
|
||||
#define PREFIX_DS 0x3e
|
||||
#define PREFIX_ES 0x26
|
||||
#define PREFIX_SS 0x36
|
||||
#define PREFIX_FS 0x64
|
||||
#define PREFIX_GS 0x65
|
||||
#define PREFIX_REPE 0xf3
|
||||
#define PREFIX_REPNE 0xf2
|
||||
#define PREFIX_LOCK 0xf0
|
||||
|
||||
/* These are to defeat the default action, giving the instruction
|
||||
no net effect: */
|
||||
#define NO_NET_DATA_EFFECT \
|
||||
{ FPU_data_address = (void *)data_operand_offset; \
|
||||
FPU_data_selector = operand_selector; }
|
||||
#define NO_NET_INSTR_EFFECT \
|
||||
{ FPU_entry_eip = ip_offset; \
|
||||
FPU_entry_op_cs = cs_selector; }
|
||||
|
||||
|
||||
typedef void (*FUNC)(void);
|
||||
typedef struct fpu_reg FPU_REG;
|
||||
typedef struct { unsigned char address_size, segment; } overrides;
|
||||
|
||||
#define st(x) ( regs[((top+x) &7 )] )
|
||||
|
||||
#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
|
||||
#define NOT_EMPTY(i) (st(i).tag != TW_Empty)
|
||||
#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty)
|
||||
|
||||
extern unsigned char FPU_rm;
|
||||
|
||||
extern char FPU_st0_tag;
|
||||
extern FPU_REG *FPU_st0_ptr;
|
||||
|
||||
/* ###### These need to be shifted to somewhere safe. */
|
||||
/* extern void *FPU_data_address; has been shifted */
|
||||
extern unsigned short FPU_data_selector;
|
||||
extern unsigned long FPU_entry_op_cs;
|
||||
|
||||
extern FPU_REG FPU_loaded_data;
|
||||
|
||||
#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; }
|
||||
|
||||
/* push() does not affect the tags */
|
||||
#define push() { top--; FPU_st0_ptr = st_new_ptr; }
|
||||
|
||||
|
||||
#define reg_move(x, y) { \
|
||||
*(short *)&((y)->sign) = *(short *)&((x)->sign); \
|
||||
*(long *)&((y)->exp) = *(long *)&((x)->exp); \
|
||||
*(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); }
|
||||
|
||||
#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
|
||||
|
||||
|
||||
/*----- Prototypes for functions written in assembler -----*/
|
||||
/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
|
||||
|
||||
asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b,
|
||||
unsigned long long *result);
|
||||
asmlinkage void poly_div2(unsigned long long *x);
|
||||
asmlinkage void poly_div4(unsigned long long *x);
|
||||
asmlinkage void poly_div16(unsigned long long *x);
|
||||
asmlinkage void polynomial(unsigned accum[], unsigned const x[],
|
||||
unsigned short const terms[][4], int const n);
|
||||
asmlinkage void normalize(FPU_REG *x);
|
||||
asmlinkage void normalize_nuo(FPU_REG *x);
|
||||
asmlinkage int reg_div(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||
FPU_REG *answ, unsigned int control_w);
|
||||
asmlinkage int reg_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||
FPU_REG *answ, unsigned int control_w);
|
||||
asmlinkage int reg_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||
FPU_REG *answ, unsigned int control_w);
|
||||
asmlinkage int reg_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||
FPU_REG *answ, unsigned int control_w);
|
||||
asmlinkage int reg_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||
FPU_REG *answ, unsigned int control_w);
|
||||
asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w);
|
||||
asmlinkage unsigned shrx(void *l, unsigned x);
|
||||
asmlinkage unsigned shrxs(void *v, unsigned x);
|
||||
asmlinkage unsigned long div_small(unsigned long long *x, unsigned long y);
|
||||
asmlinkage void round_reg(FPU_REG *arg, unsigned int extent,
|
||||
unsigned int control_w);
|
||||
|
||||
#ifndef MAKING_PROTO
|
||||
#include "fpu_proto.h"
|
||||
#endif
|
||||
|
||||
#endif __ASSEMBLER__
|
||||
|
||||
#endif _FPU_EMU_H_
|
622
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_entry.c
Normal file
622
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_entry.c
Normal file
|
@ -0,0 +1,622 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_entry.c |
|
||||
| |
|
||||
| The entry function for wm-FPU-emu |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| See the files "README" and "COPYING" for further copyright and warranty |
|
||||
| information. |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Note: |
|
||||
| The file contains code which accesses user memory. |
|
||||
| Emulator static data may change when user memory is accessed, due to |
|
||||
| other processes using the emulator while swapping is in progress. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| math_emulate() is the sole entry point for wm-FPU-emu |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include <linux/signal.h>
|
||||
#include <linux/segment.h>
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "exception.h"
|
||||
#include "control_w.h"
|
||||
#include "status_w.h"
|
||||
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
|
||||
|
||||
#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
|
||||
|
||||
/* WARNING: These codes are not documented by Intel in their 80486 manual
|
||||
and may not work on FPU clones or later Intel FPUs. */
|
||||
|
||||
/* Changes to support the un-doc codes provided by Linus Torvalds. */
|
||||
|
||||
#define _d9_d8_ fstp_i /* unofficial code (19) */
|
||||
#define _dc_d0_ fcom_st /* unofficial code (14) */
|
||||
#define _dc_d8_ fcompst /* unofficial code (1c) */
|
||||
#define _dd_c8_ fxch_i /* unofficial code (0d) */
|
||||
#define _de_d0_ fcompst /* unofficial code (16) */
|
||||
#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
|
||||
#define _df_c8_ fxch_i /* unofficial code (0f) */
|
||||
#define _df_d0_ fstp_i /* unofficial code (17) */
|
||||
#define _df_d8_ fstp_i /* unofficial code (1f) */
|
||||
|
||||
static FUNC const st_instr_table[64] = {
|
||||
fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
|
||||
fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
|
||||
fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
|
||||
fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
|
||||
fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
|
||||
fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
|
||||
fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
|
||||
fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
|
||||
};
|
||||
|
||||
#else /* Support only documented FPU op-codes */
|
||||
|
||||
static FUNC const st_instr_table[64] = {
|
||||
fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
|
||||
fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
|
||||
fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
|
||||
fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
|
||||
fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
|
||||
fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
|
||||
fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
|
||||
fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
|
||||
};
|
||||
|
||||
#endif NO_UNDOC_CODE
|
||||
|
||||
|
||||
#define _NONE_ 0 /* Take no special action */
|
||||
#define _REG0_ 1 /* Need to check for not empty st(0) */
|
||||
#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
|
||||
#define _REGi_ 0 /* Uses st(rm) */
|
||||
#define _PUSH_ 3 /* Need to check for space to push onto stack */
|
||||
#define _null_ 4 /* Function illegal or not implemented */
|
||||
#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
|
||||
#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
|
||||
#define _REGIc 0 /* Compare st(0) and st(rm) */
|
||||
#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
|
||||
|
||||
#ifndef NO_UNDOC_CODE
|
||||
|
||||
/* Un-documented FPU op-codes supported by default. (see above) */
|
||||
|
||||
static unsigned char const type_table[64] = {
|
||||
_REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
|
||||
_REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
|
||||
_REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
|
||||
_REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
|
||||
_REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
|
||||
_REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
|
||||
_REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
|
||||
_REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
|
||||
};
|
||||
|
||||
#else /* Support only documented FPU op-codes */
|
||||
|
||||
static unsigned char const type_table[64] = {
|
||||
_REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
|
||||
_REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
|
||||
_REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
|
||||
_REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
|
||||
_REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
|
||||
_REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
|
||||
_REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
|
||||
_REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
|
||||
};
|
||||
|
||||
#endif NO_UNDOC_CODE
|
||||
|
||||
|
||||
/* Be careful when using any of these global variables...
|
||||
they might change if swapping is triggered */
|
||||
unsigned char FPU_rm;
|
||||
char FPU_st0_tag;
|
||||
FPU_REG *FPU_st0_ptr;
|
||||
|
||||
/* ######## To be shifted */
|
||||
unsigned long FPU_entry_op_cs;
|
||||
unsigned short FPU_data_selector;
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
char emulating=0;
|
||||
#endif PARANOID
|
||||
|
||||
static int valid_prefix(unsigned char *byte, overrides *override);
|
||||
|
||||
|
||||
asmlinkage void math_emulate(long arg)
|
||||
{
|
||||
unsigned char FPU_modrm, byte1;
|
||||
overrides override;
|
||||
int unmasked;
|
||||
|
||||
#ifdef PARANOID
|
||||
if ( emulating )
|
||||
{
|
||||
printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
|
||||
}
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
#endif PARANOID
|
||||
|
||||
if (!current->used_math)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < 8; i++ )
|
||||
{
|
||||
/* Make sure that the registers are compatible
|
||||
with the assumptions of the emulator. */
|
||||
regs[i].exp = 0;
|
||||
regs[i].sigh = 0x80000000;
|
||||
}
|
||||
finit();
|
||||
current->used_math = 1;
|
||||
}
|
||||
|
||||
SETUP_DATA_AREA(arg);
|
||||
|
||||
FPU_ORIG_EIP = FPU_EIP;
|
||||
|
||||
/* We cannot handle emulation in v86-mode */
|
||||
if (FPU_EFLAGS & 0x00020000)
|
||||
{
|
||||
math_abort(FPU_info,SIGILL);
|
||||
}
|
||||
|
||||
/* user code space? */
|
||||
if (FPU_CS == KERNEL_CS)
|
||||
{
|
||||
printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
|
||||
panic("Math emulation needed in kernel");
|
||||
}
|
||||
|
||||
/* We cannot handle multiple segments yet */
|
||||
if (FPU_CS != USER_CS || FPU_DS != USER_DS)
|
||||
{
|
||||
math_abort(FPU_info,SIGILL);
|
||||
}
|
||||
|
||||
FPU_lookahead = 1;
|
||||
if (current->flags & PF_PTRACED)
|
||||
FPU_lookahead = 0;
|
||||
|
||||
if ( !valid_prefix(&byte1, &override) )
|
||||
{
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
printk("FPU emulator: Unknown prefix byte 0x%02x\n", byte1);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
EXCEPTION(EX_INTERNAL|0x126);
|
||||
math_abort(FPU_info,SIGILL);
|
||||
}
|
||||
|
||||
do_another_FPU_instruction:
|
||||
|
||||
FPU_EIP++; /* We have fetched the prefix and first code bytes. */
|
||||
|
||||
#ifdef PECULIAR_486
|
||||
/* It would be more logical to do this only in get_address(),
|
||||
but although it is supposed to be undefined for many fpu
|
||||
instructions, an 80486 behaves as if this were done here: */
|
||||
FPU_data_selector = FPU_DS;
|
||||
#endif PECULIAR_486
|
||||
|
||||
if ( (byte1 & 0xf8) != 0xd8 )
|
||||
{
|
||||
if ( byte1 == FWAIT_OPCODE )
|
||||
{
|
||||
if (partial_status & SW_Summary)
|
||||
goto do_the_FPU_interrupt;
|
||||
else
|
||||
goto FPU_fwait_done;
|
||||
}
|
||||
#ifdef PARANOID
|
||||
EXCEPTION(EX_INTERNAL|0x128);
|
||||
math_abort(FPU_info,SIGILL);
|
||||
#endif PARANOID
|
||||
}
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(1);
|
||||
FPU_modrm = get_fs_byte((unsigned short *) FPU_EIP);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
FPU_EIP++;
|
||||
|
||||
if (partial_status & SW_Summary)
|
||||
{
|
||||
/* Ignore the error for now if the current instruction is a no-wait
|
||||
control instruction */
|
||||
/* The 80486 manual contradicts itself on this topic,
|
||||
but a real 80486 uses the following instructions:
|
||||
fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
|
||||
*/
|
||||
unsigned short code = (FPU_modrm << 8) | byte1;
|
||||
if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
|
||||
(((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
|
||||
fnstsw */
|
||||
((code & 0xc000) != 0xc000))) ) )
|
||||
{
|
||||
/*
|
||||
* We need to simulate the action of the kernel to FPU
|
||||
* interrupts here.
|
||||
* Currently, the "real FPU" part of the kernel (0.99.10)
|
||||
* clears the exception flags, sets the registers to empty,
|
||||
* and passes information back to the interrupted process
|
||||
* via the cs selector and operand selector, so we do the same.
|
||||
*/
|
||||
do_the_FPU_interrupt:
|
||||
cs_selector &= 0xffff0000;
|
||||
cs_selector |= status_word();
|
||||
operand_selector = tag_word();
|
||||
partial_status = 0;
|
||||
top = 0;
|
||||
{
|
||||
int r;
|
||||
for (r = 0; r < 8; r++)
|
||||
{
|
||||
regs[r].tag = TW_Empty;
|
||||
}
|
||||
}
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
current->tss.trap_no = 16;
|
||||
current->tss.error_code = 0;
|
||||
send_sig(SIGFPE, current, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FPU_entry_eip = FPU_ORIG_EIP;
|
||||
|
||||
FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
|
||||
|
||||
FPU_rm = FPU_modrm & 7;
|
||||
|
||||
if ( FPU_modrm < 0300 )
|
||||
{
|
||||
/* All of these instructions use the mod/rm byte to get a data address */
|
||||
get_address(FPU_modrm, override);
|
||||
if ( !(byte1 & 1) )
|
||||
{
|
||||
unsigned short status1 = partial_status;
|
||||
FPU_st0_ptr = &st(0);
|
||||
FPU_st0_tag = FPU_st0_ptr->tag;
|
||||
|
||||
/* Stack underflow has priority */
|
||||
if ( NOT_EMPTY_0 )
|
||||
{
|
||||
unmasked = 0; /* Do this here to stop compiler warnings. */
|
||||
switch ( (byte1 >> 1) & 3 )
|
||||
{
|
||||
case 0:
|
||||
unmasked = reg_load_single(override);
|
||||
break;
|
||||
case 1:
|
||||
reg_load_int32(override);
|
||||
break;
|
||||
case 2:
|
||||
unmasked = reg_load_double(override);
|
||||
break;
|
||||
case 3:
|
||||
reg_load_int16(override);
|
||||
break;
|
||||
}
|
||||
|
||||
/* No more access to user memory, it is safe
|
||||
to use static data now */
|
||||
FPU_st0_ptr = &st(0);
|
||||
FPU_st0_tag = FPU_st0_ptr->tag;
|
||||
|
||||
/* NaN operands have the next priority. */
|
||||
/* We have to delay looking at st(0) until after
|
||||
loading the data, because that data might contain an SNaN */
|
||||
if ( (FPU_st0_tag == TW_NaN) ||
|
||||
(FPU_loaded_data.tag == TW_NaN) )
|
||||
{
|
||||
/* Restore the status word; we might have loaded a
|
||||
denormal. */
|
||||
partial_status = status1;
|
||||
if ( (FPU_modrm & 0x30) == 0x10 )
|
||||
{
|
||||
/* fcom or fcomp */
|
||||
EXCEPTION(EX_Invalid);
|
||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||
if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
|
||||
pop(); /* fcomp, masked, so we pop. */
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PECULIAR_486
|
||||
/* This is not really needed, but gives behaviour
|
||||
identical to an 80486 */
|
||||
if ( (FPU_modrm & 0x28) == 0x20 )
|
||||
/* fdiv or fsub */
|
||||
real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
|
||||
FPU_st0_ptr);
|
||||
else
|
||||
#endif PECULIAR_486
|
||||
/* fadd, fdivr, fmul, or fsubr */
|
||||
real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
|
||||
FPU_st0_ptr);
|
||||
}
|
||||
goto reg_mem_instr_done;
|
||||
}
|
||||
|
||||
if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
|
||||
{
|
||||
/* Is not a comparison instruction. */
|
||||
if ( (FPU_modrm & 0x38) == 0x38 )
|
||||
{
|
||||
/* fdivr */
|
||||
if ( (FPU_st0_tag == TW_Zero) &&
|
||||
(FPU_loaded_data.tag == TW_Valid) )
|
||||
{
|
||||
if ( divide_by_zero(FPU_loaded_data.sign,
|
||||
FPU_st0_ptr) )
|
||||
{
|
||||
/* We use the fact here that the unmasked
|
||||
exception in the loaded data was for a
|
||||
denormal operand */
|
||||
/* Restore the state of the denormal op bit */
|
||||
partial_status &= ~SW_Denorm_Op;
|
||||
partial_status |= status1 & SW_Denorm_Op;
|
||||
}
|
||||
}
|
||||
}
|
||||
goto reg_mem_instr_done;
|
||||
}
|
||||
|
||||
switch ( (FPU_modrm >> 3) & 7 )
|
||||
{
|
||||
case 0: /* fadd */
|
||||
clear_C1();
|
||||
reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
|
||||
control_word);
|
||||
break;
|
||||
case 1: /* fmul */
|
||||
clear_C1();
|
||||
reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
|
||||
control_word);
|
||||
break;
|
||||
case 2: /* fcom */
|
||||
compare_st_data();
|
||||
break;
|
||||
case 3: /* fcomp */
|
||||
if ( !compare_st_data() && !unmasked )
|
||||
pop();
|
||||
break;
|
||||
case 4: /* fsub */
|
||||
clear_C1();
|
||||
reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
|
||||
control_word);
|
||||
break;
|
||||
case 5: /* fsubr */
|
||||
clear_C1();
|
||||
reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
|
||||
control_word);
|
||||
break;
|
||||
case 6: /* fdiv */
|
||||
clear_C1();
|
||||
reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
|
||||
control_word);
|
||||
break;
|
||||
case 7: /* fdivr */
|
||||
clear_C1();
|
||||
if ( FPU_st0_tag == TW_Zero )
|
||||
partial_status = status1; /* Undo any denorm tag,
|
||||
zero-divide has priority. */
|
||||
reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
|
||||
control_word);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (FPU_modrm & 0x30) == 0x10 )
|
||||
{
|
||||
/* The instruction is fcom or fcomp */
|
||||
EXCEPTION(EX_StackUnder);
|
||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||
if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
|
||||
pop(); /* fcomp */
|
||||
}
|
||||
else
|
||||
stack_underflow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, override);
|
||||
}
|
||||
|
||||
reg_mem_instr_done:
|
||||
|
||||
#ifndef PECULIAR_486
|
||||
*(unsigned short *)&operand_selector = FPU_data_selector;
|
||||
#endif PECULIAR_486
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* None of these instructions access user memory */
|
||||
unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
|
||||
|
||||
#ifdef PECULIAR_486
|
||||
/* This is supposed to be undefined, but a real 80486 seems
|
||||
to do this: */
|
||||
FPU_data_address = 0;
|
||||
#endif PECULIAR_486
|
||||
|
||||
FPU_st0_ptr = &st(0);
|
||||
FPU_st0_tag = FPU_st0_ptr->tag;
|
||||
switch ( type_table[(int) instr_index] )
|
||||
{
|
||||
case _NONE_: /* also _REGIc: _REGIn */
|
||||
break;
|
||||
case _REG0_:
|
||||
if ( !NOT_EMPTY_0 )
|
||||
{
|
||||
stack_underflow();
|
||||
goto FPU_instruction_done;
|
||||
}
|
||||
break;
|
||||
case _REGIi:
|
||||
if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
|
||||
{
|
||||
stack_underflow_i(FPU_rm);
|
||||
goto FPU_instruction_done;
|
||||
}
|
||||
break;
|
||||
case _REGIp:
|
||||
if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
|
||||
{
|
||||
stack_underflow_pop(FPU_rm);
|
||||
goto FPU_instruction_done;
|
||||
}
|
||||
break;
|
||||
case _REGI_:
|
||||
if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
|
||||
{
|
||||
stack_underflow();
|
||||
goto FPU_instruction_done;
|
||||
}
|
||||
break;
|
||||
case _PUSH_: /* Only used by the fld st(i) instruction */
|
||||
break;
|
||||
case _null_:
|
||||
FPU_illegal();
|
||||
goto FPU_instruction_done;
|
||||
default:
|
||||
EXCEPTION(EX_INTERNAL|0x111);
|
||||
goto FPU_instruction_done;
|
||||
}
|
||||
(*st_instr_table[(int) instr_index])();
|
||||
}
|
||||
|
||||
FPU_instruction_done:
|
||||
|
||||
ip_offset = FPU_entry_eip;
|
||||
cs_selector = FPU_entry_op_cs;
|
||||
data_operand_offset = (unsigned long)FPU_data_address;
|
||||
#ifdef PECULIAR_486
|
||||
*(unsigned short *)&operand_selector = FPU_data_selector;
|
||||
#endif PECULIAR_486
|
||||
|
||||
FPU_fwait_done:
|
||||
|
||||
#ifdef DEBUG
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
emu_printall();
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
#endif DEBUG
|
||||
|
||||
if (FPU_lookahead && !need_resched)
|
||||
{
|
||||
FPU_ORIG_EIP = FPU_EIP;
|
||||
if ( valid_prefix(&byte1, &override) )
|
||||
goto do_another_FPU_instruction;
|
||||
}
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
}
|
||||
|
||||
|
||||
/* Support for prefix bytes is not yet complete. To properly handle
|
||||
all prefix bytes, further changes are needed in the emulator code
|
||||
which accesses user address space. Access to separate segments is
|
||||
important for msdos emulation. */
|
||||
static int valid_prefix(unsigned char *Byte, overrides *override)
|
||||
{
|
||||
unsigned char byte;
|
||||
unsigned long ip = FPU_EIP;
|
||||
|
||||
*override = (overrides) { 0, PREFIX_DS }; /* defaults */
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(1);
|
||||
byte = get_fs_byte((unsigned char *) FPU_EIP);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
switch ( byte )
|
||||
{
|
||||
case ADDR_SIZE_PREFIX:
|
||||
override->address_size = ADDR_SIZE_PREFIX;
|
||||
goto do_next_byte;
|
||||
case PREFIX_CS:
|
||||
override->segment = PREFIX_CS;
|
||||
goto do_next_byte;
|
||||
case PREFIX_ES:
|
||||
override->segment = PREFIX_ES;
|
||||
goto do_next_byte;
|
||||
case PREFIX_SS:
|
||||
override->segment = PREFIX_SS;
|
||||
goto do_next_byte;
|
||||
case PREFIX_FS:
|
||||
override->segment = PREFIX_FS;
|
||||
goto do_next_byte;
|
||||
case PREFIX_GS:
|
||||
override->segment = PREFIX_GS;
|
||||
goto do_next_byte;
|
||||
|
||||
case PREFIX_DS: /* Redundant unless preceded by another override. */
|
||||
override->segment = PREFIX_DS;
|
||||
|
||||
/* rep.. prefixes have no meaning for FPU instructions */
|
||||
case PREFIX_LOCK:
|
||||
case PREFIX_REPE:
|
||||
case PREFIX_REPNE:
|
||||
case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */
|
||||
do_next_byte:
|
||||
FPU_EIP++;
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(1);
|
||||
byte = get_fs_byte((unsigned char *) (FPU_EIP));
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
break;
|
||||
case FWAIT_OPCODE:
|
||||
*Byte = byte;
|
||||
return 1;
|
||||
default:
|
||||
if ( (byte & 0xf8) == 0xd8 )
|
||||
{
|
||||
*Byte = byte;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
FPU_EIP = ip;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __math_abort(struct info * info, unsigned int signal)
|
||||
{
|
||||
FPU_EIP = FPU_ORIG_EIP;
|
||||
current->tss.trap_no = 16;
|
||||
current->tss.error_code = 0;
|
||||
send_sig(signal,current,1);
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
__asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
|
||||
#ifdef PARANOID
|
||||
printk("ERROR: wm-FPU-emu math_abort failed!\n");
|
||||
#endif PARANOID
|
||||
}
|
127
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_etc.c
Normal file
127
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_etc.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_etc.c |
|
||||
| |
|
||||
| Implement a few FPU instructions. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "status_w.h"
|
||||
#include "reg_constant.h"
|
||||
|
||||
|
||||
static void fchs(void)
|
||||
{
|
||||
if ( NOT_EMPTY_0 )
|
||||
{
|
||||
FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
|
||||
clear_C1();
|
||||
}
|
||||
else
|
||||
stack_underflow();
|
||||
}
|
||||
|
||||
static void fabs(void)
|
||||
{
|
||||
if ( FPU_st0_tag ^ TW_Empty )
|
||||
{
|
||||
FPU_st0_ptr->sign = SIGN_POS;
|
||||
clear_C1();
|
||||
}
|
||||
else
|
||||
stack_underflow();
|
||||
}
|
||||
|
||||
|
||||
static void ftst_(void)
|
||||
{
|
||||
switch (FPU_st0_tag)
|
||||
{
|
||||
case TW_Zero:
|
||||
setcc(SW_C3);
|
||||
break;
|
||||
case TW_Valid:
|
||||
if (FPU_st0_ptr->sign == SIGN_POS)
|
||||
setcc(0);
|
||||
else
|
||||
setcc(SW_C0);
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
|
||||
{
|
||||
#ifdef PECULIAR_486
|
||||
/* This is wierd! */
|
||||
if (FPU_st0_ptr->sign == SIGN_POS)
|
||||
setcc(SW_C3);
|
||||
#endif PECULIAR_486
|
||||
return;
|
||||
}
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
break;
|
||||
case TW_NaN:
|
||||
setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
|
||||
EXCEPTION(EX_Invalid);
|
||||
break;
|
||||
case TW_Infinity:
|
||||
if (FPU_st0_ptr->sign == SIGN_POS)
|
||||
setcc(0);
|
||||
else
|
||||
setcc(SW_C0);
|
||||
break;
|
||||
case TW_Empty:
|
||||
setcc(SW_C0|SW_C2|SW_C3);
|
||||
EXCEPTION(EX_StackUnder);
|
||||
break;
|
||||
default:
|
||||
setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
|
||||
EXCEPTION(EX_INTERNAL|0x14);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fxam(void)
|
||||
{
|
||||
int c=0;
|
||||
switch (FPU_st0_tag)
|
||||
{
|
||||
case TW_Empty:
|
||||
c = SW_C3|SW_C0;
|
||||
break;
|
||||
case TW_Zero:
|
||||
c = SW_C3;
|
||||
break;
|
||||
case TW_Valid:
|
||||
/* This will need to be changed if TW_Denormal is ever used. */
|
||||
if ( FPU_st0_ptr->exp <= EXP_UNDER )
|
||||
c = SW_C2|SW_C3; /* Denormal */
|
||||
else
|
||||
c = SW_C2;
|
||||
break;
|
||||
case TW_NaN:
|
||||
c = SW_C0;
|
||||
break;
|
||||
case TW_Infinity:
|
||||
c = SW_C2|SW_C0;
|
||||
break;
|
||||
}
|
||||
if (FPU_st0_ptr->sign == SIGN_NEG)
|
||||
c |= SW_C1;
|
||||
setcc(c);
|
||||
}
|
||||
|
||||
static FUNC const fp_etc_table[] = {
|
||||
fchs, fabs, FPU_illegal, FPU_illegal, ftst_, fxam, FPU_illegal, FPU_illegal
|
||||
};
|
||||
|
||||
void fp_etc()
|
||||
{
|
||||
(fp_etc_table[FPU_rm])();
|
||||
}
|
131
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_proto.h
Normal file
131
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_proto.h
Normal file
|
@ -0,0 +1,131 @@
|
|||
/* errors.c */
|
||||
extern void Un_impl(void);
|
||||
extern void FPU_illegal(void);
|
||||
extern void emu_printall(void);
|
||||
extern void stack_overflow(void);
|
||||
extern void stack_underflow(void);
|
||||
extern void stack_underflow_i(int i);
|
||||
extern void stack_underflow_pop(int i);
|
||||
extern int set_precision_flag(int flags);
|
||||
asmlinkage void exception(int n);
|
||||
asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest);
|
||||
asmlinkage int arith_invalid(FPU_REG *dest);
|
||||
asmlinkage int divide_by_zero(int sign, FPU_REG *dest);
|
||||
asmlinkage void set_precision_flag_up(void);
|
||||
asmlinkage void set_precision_flag_down(void);
|
||||
asmlinkage int denormal_operand(void);
|
||||
asmlinkage int arith_overflow(FPU_REG *dest);
|
||||
asmlinkage int arith_underflow(FPU_REG *dest);
|
||||
|
||||
/* fpu_arith.c */
|
||||
extern void fadd__(void);
|
||||
extern void fmul__(void);
|
||||
extern void fsub__(void);
|
||||
extern void fsubr_(void);
|
||||
extern void fdiv__(void);
|
||||
extern void fdivr_(void);
|
||||
extern void fadd_i(void);
|
||||
extern void fmul_i(void);
|
||||
extern void fsubri(void);
|
||||
extern void fsub_i(void);
|
||||
extern void fdivri(void);
|
||||
extern void fdiv_i(void);
|
||||
extern void faddp_(void);
|
||||
extern void fmulp_(void);
|
||||
extern void fsubrp(void);
|
||||
extern void fsubp_(void);
|
||||
extern void fdivrp(void);
|
||||
extern void fdivp_(void);
|
||||
|
||||
/* fpu_aux.c */
|
||||
extern void fclex(void);
|
||||
extern void finit(void);
|
||||
extern void finit_(void);
|
||||
extern void fstsw_(void);
|
||||
extern void fp_nop(void);
|
||||
extern void fld_i_(void);
|
||||
extern void fxch_i(void);
|
||||
extern void ffree_(void);
|
||||
extern void ffreep(void);
|
||||
extern void fst_i_(void);
|
||||
extern void fstp_i(void);
|
||||
|
||||
/* fpu_entry.c */
|
||||
asmlinkage void math_emulate(long arg);
|
||||
extern void __math_abort(struct info *info, unsigned int signal);
|
||||
|
||||
/* fpu_etc.c */
|
||||
extern void fp_etc(void);
|
||||
|
||||
/* fpu_trig.c */
|
||||
extern void convert_l2reg(long const *arg, FPU_REG *dest);
|
||||
extern void trig_a(void);
|
||||
extern void trig_b(void);
|
||||
|
||||
/* get_address.c */
|
||||
extern void get_address(unsigned char FPU_modrm, overrides override);
|
||||
|
||||
/* load_store.c */
|
||||
extern void load_store_instr(char type, overrides override);
|
||||
|
||||
/* poly_2xm1.c */
|
||||
extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
|
||||
|
||||
/* poly_atan.c */
|
||||
extern void poly_atan(FPU_REG *arg);
|
||||
extern void poly_add_1(FPU_REG *src);
|
||||
|
||||
/* poly_l2.c */
|
||||
extern void poly_l2(FPU_REG const *arg, FPU_REG *result);
|
||||
extern int poly_l2p1(FPU_REG const *arg, FPU_REG *result);
|
||||
|
||||
/* poly_sin.c */
|
||||
extern void poly_sine(FPU_REG const *arg, FPU_REG *result);
|
||||
|
||||
/* poly_tan.c */
|
||||
extern void poly_tan(FPU_REG const *arg, FPU_REG *result, int invert);
|
||||
|
||||
/* reg_add_sub.c */
|
||||
extern int reg_add(FPU_REG const *a, FPU_REG const *b,
|
||||
FPU_REG *dest, int control_w);
|
||||
extern int reg_sub(FPU_REG const *a, FPU_REG const *b,
|
||||
FPU_REG *dest, int control_w);
|
||||
|
||||
/* reg_compare.c */
|
||||
extern int compare(FPU_REG const *b);
|
||||
extern int compare_st_data(void);
|
||||
extern void fcom_st(void);
|
||||
extern void fcompst(void);
|
||||
extern void fcompp(void);
|
||||
extern void fucom_(void);
|
||||
extern void fucomp(void);
|
||||
extern void fucompp(void);
|
||||
|
||||
/* reg_constant.c */
|
||||
extern void fconst(void);
|
||||
|
||||
/* reg_ld_str.c */
|
||||
extern int reg_load_extended(overrides override);
|
||||
extern int reg_load_double(overrides override);
|
||||
extern int reg_load_single(overrides override);
|
||||
extern void reg_load_int64(overrides override);
|
||||
extern void reg_load_int32(overrides override);
|
||||
extern void reg_load_int16(overrides override);
|
||||
extern void reg_load_bcd(overrides override);
|
||||
extern int reg_store_extended(overrides override);
|
||||
extern int reg_store_double(overrides override);
|
||||
extern int reg_store_single(overrides override);
|
||||
extern int reg_store_int64(overrides override);
|
||||
extern int reg_store_int32(overrides override);
|
||||
extern int reg_store_int16(overrides override);
|
||||
extern int reg_store_bcd(overrides override);
|
||||
extern int round_to_int(FPU_REG *r);
|
||||
extern char *fldenv(void);
|
||||
extern void frstor(void);
|
||||
extern unsigned short tag_word(void);
|
||||
extern char *fstenv(void);
|
||||
extern void fsave(void);
|
||||
|
||||
/* reg_mul.c */
|
||||
extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
|
||||
FPU_REG *dest, unsigned int control_w);
|
65
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_system.h
Normal file
65
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_system.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| fpu_system.h |
|
||||
| |
|
||||
| Copyright (C) 1992,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _FPU_SYSTEM_H
|
||||
#define _FPU_SYSTEM_H
|
||||
|
||||
/* system dependent definitions */
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/* This sets the pointer FPU_info to point to the argument part
|
||||
of the stack frame of math_emulate() */
|
||||
#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg
|
||||
|
||||
#define I387 (current->tss.i387)
|
||||
#define FPU_info (I387.soft.info)
|
||||
|
||||
#define FPU_CS (*(unsigned short *) &(FPU_info->___cs))
|
||||
#define FPU_DS (*(unsigned short *) &(FPU_info->___ds))
|
||||
#define FPU_EAX (FPU_info->___eax)
|
||||
#define FPU_EFLAGS (FPU_info->___eflags)
|
||||
#define FPU_EIP (FPU_info->___eip)
|
||||
#define FPU_ORIG_EIP (FPU_info->___orig_eip)
|
||||
|
||||
#define FPU_lookahead (I387.soft.lookahead)
|
||||
#define FPU_entry_eip (I387.soft.entry_eip)
|
||||
|
||||
#define partial_status (I387.soft.swd)
|
||||
#define control_word (I387.soft.cwd)
|
||||
#define regs (I387.soft.regs)
|
||||
#define top (I387.soft.top)
|
||||
|
||||
#define ip_offset (I387.soft.fip)
|
||||
#define cs_selector (I387.soft.fcs)
|
||||
#define data_operand_offset (I387.soft.foo)
|
||||
#define operand_selector (I387.soft.fos)
|
||||
|
||||
#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
|
||||
math_abort(FPU_info,SIGSEGV)
|
||||
|
||||
#undef FPU_IGNORE_CODE_SEGV
|
||||
#ifdef FPU_IGNORE_CODE_SEGV
|
||||
/* verify_area() is very expensive, and causes the emulator to run
|
||||
about 20% slower if applied to the code. Anyway, errors due to bad
|
||||
code addresses should be much rarer than errors due to bad data
|
||||
addresses. */
|
||||
#define FPU_code_verify_area(z)
|
||||
#else
|
||||
/* A simpler test than verify_area() can probably be done for
|
||||
FPU_code_verify_area() because the only possible error is to step
|
||||
past the upper boundary of a legal code area. */
|
||||
#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
|
||||
#endif
|
||||
|
||||
/* ######## temporary and ugly ;-) */
|
||||
#define FPU_data_address ((void *)(I387.soft.twd))
|
||||
|
||||
#endif
|
1741
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_trig.c
Normal file
1741
source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_trig.c
Normal file
File diff suppressed because it is too large
Load diff
197
source/THIRDPARTY/linux-old/drivers/FPU-emu/get_address.c
Normal file
197
source/THIRDPARTY/linux-old/drivers/FPU-emu/get_address.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| get_address.c |
|
||||
| |
|
||||
| Get the effective address from an FPU instruction. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Note: |
|
||||
| The file contains code which accesses user memory. |
|
||||
| Emulator static data may change when user memory is accessed, due to |
|
||||
| other processes using the emulator while swapping is in progress. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "fpu_emu.h"
|
||||
|
||||
static int reg_offset[] = {
|
||||
offsetof(struct info,___eax),
|
||||
offsetof(struct info,___ecx),
|
||||
offsetof(struct info,___edx),
|
||||
offsetof(struct info,___ebx),
|
||||
offsetof(struct info,___esp),
|
||||
offsetof(struct info,___ebp),
|
||||
offsetof(struct info,___esi),
|
||||
offsetof(struct info,___edi)
|
||||
};
|
||||
|
||||
#define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
|
||||
|
||||
|
||||
/* Decode the SIB byte. This function assumes mod != 0 */
|
||||
static void *sib(int mod)
|
||||
{
|
||||
unsigned char ss,index,base;
|
||||
long offset;
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(1);
|
||||
base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
FPU_EIP++;
|
||||
ss = base >> 6;
|
||||
index = (base >> 3) & 7;
|
||||
base &= 7;
|
||||
|
||||
if ((mod == 0) && (base == 5))
|
||||
offset = 0; /* No base register */
|
||||
else
|
||||
offset = REG_(base);
|
||||
|
||||
if (index == 4)
|
||||
{
|
||||
/* No index register */
|
||||
/* A non-zero ss is illegal */
|
||||
if ( ss )
|
||||
EXCEPTION(EX_Invalid);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += (REG_(index)) << ss;
|
||||
}
|
||||
|
||||
if (mod == 1)
|
||||
{
|
||||
/* 8 bit signed displacement */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(1);
|
||||
offset += (signed char) get_fs_byte((char *) FPU_EIP);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
FPU_EIP++;
|
||||
}
|
||||
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
|
||||
{
|
||||
/* 32 bit displacment */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(4);
|
||||
offset += (signed) get_fs_long((unsigned long *) FPU_EIP);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
FPU_EIP += 4;
|
||||
}
|
||||
|
||||
return (void *) offset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
MOD R/M byte: MOD == 3 has a special use for the FPU
|
||||
SIB byte used iff R/M = 100b
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
..... ......... .........
|
||||
MOD OPCODE(2) R/M
|
||||
|
||||
|
||||
SIB byte
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
..... ......... .........
|
||||
SS INDEX BASE
|
||||
|
||||
*/
|
||||
|
||||
void get_address(unsigned char FPU_modrm, overrides override)
|
||||
{
|
||||
unsigned char mod;
|
||||
long *cpu_reg_ptr;
|
||||
int offset = 0; /* Initialized just to stop compiler warnings. */
|
||||
|
||||
#ifndef PECULIAR_486
|
||||
/* This is a reasonable place to do this */
|
||||
FPU_data_selector = FPU_DS;
|
||||
#endif PECULIAR_486
|
||||
|
||||
mod = (FPU_modrm >> 6) & 3;
|
||||
|
||||
if (FPU_rm == 4 && mod != 3)
|
||||
{
|
||||
FPU_data_address = sib(mod);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_reg_ptr = & REG_(FPU_rm);
|
||||
switch (mod)
|
||||
{
|
||||
case 0:
|
||||
if (FPU_rm == 5)
|
||||
{
|
||||
/* Special case: disp16 or disp32 */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
if ( override.address_size == ADDR_SIZE_PREFIX )
|
||||
{
|
||||
FPU_code_verify_area(2);
|
||||
offset = get_fs_word((unsigned short *) FPU_EIP);
|
||||
FPU_EIP += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FPU_code_verify_area(4);
|
||||
offset = get_fs_long((unsigned long *) FPU_EIP);
|
||||
FPU_EIP += 4;
|
||||
}
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
FPU_data_address = (void *) offset;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
FPU_data_address = (void *)*cpu_reg_ptr; /* Just return the contents
|
||||
of the cpu register */
|
||||
return;
|
||||
}
|
||||
case 1:
|
||||
/* 8 bit signed displacement */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_code_verify_area(1);
|
||||
offset = (signed char) get_fs_byte((char *) FPU_EIP);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
FPU_EIP++;
|
||||
break;
|
||||
case 2:
|
||||
/* 16 or 32 bit displacement */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
if ( override.address_size == ADDR_SIZE_PREFIX )
|
||||
{
|
||||
FPU_code_verify_area(2);
|
||||
offset = (signed) get_fs_word((unsigned short *) FPU_EIP);
|
||||
FPU_EIP += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FPU_code_verify_area(4);
|
||||
offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
|
||||
FPU_EIP += 4;
|
||||
}
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
break;
|
||||
case 3:
|
||||
/* Not legal for the FPU */
|
||||
EXCEPTION(EX_Invalid);
|
||||
}
|
||||
|
||||
FPU_data_address = offset + (char *)*cpu_reg_ptr;
|
||||
if ( override.address_size == ADDR_SIZE_PREFIX )
|
||||
FPU_data_address = (void *)((long)FPU_data_address & 0xffff);
|
||||
}
|
237
source/THIRDPARTY/linux-old/drivers/FPU-emu/load_store.c
Normal file
237
source/THIRDPARTY/linux-old/drivers/FPU-emu/load_store.c
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| load_store.c |
|
||||
| |
|
||||
| This file contains most of the code to interpret the FPU instructions |
|
||||
| which load and store from user memory. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Note: |
|
||||
| The file contains code which accesses user memory. |
|
||||
| Emulator static data may change when user memory is accessed, due to |
|
||||
| other processes using the emulator while swapping is in progress. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "status_w.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
#define _NONE_ 0 /* FPU_st0_ptr etc not needed */
|
||||
#define _REG0_ 1 /* Will be storing st(0) */
|
||||
#define _PUSH_ 3 /* Need to check for space to push onto stack */
|
||||
#define _null_ 4 /* Function illegal or not implemented */
|
||||
|
||||
#define pop_0() { pop_ptr->tag = TW_Empty; top++; }
|
||||
|
||||
|
||||
static unsigned char const type_table[32] = {
|
||||
_PUSH_, _PUSH_, _PUSH_, _PUSH_,
|
||||
_null_, _null_, _null_, _null_,
|
||||
_REG0_, _REG0_, _REG0_, _REG0_,
|
||||
_REG0_, _REG0_, _REG0_, _REG0_,
|
||||
_NONE_, _null_, _NONE_, _PUSH_,
|
||||
_NONE_, _PUSH_, _null_, _PUSH_,
|
||||
_NONE_, _null_, _NONE_, _REG0_,
|
||||
_NONE_, _REG0_, _NONE_, _REG0_
|
||||
};
|
||||
|
||||
void load_store_instr(char type, overrides override)
|
||||
{
|
||||
FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't
|
||||
change if the emulator is re-entered. */
|
||||
|
||||
pop_ptr = NULL; /* Initialized just to stop compiler warnings. */
|
||||
switch ( type_table[(int) (unsigned) type] )
|
||||
{
|
||||
case _NONE_:
|
||||
break;
|
||||
case _REG0_:
|
||||
pop_ptr = &st(0); /* Some of these instructions pop after
|
||||
storing */
|
||||
|
||||
FPU_st0_ptr = pop_ptr; /* Set the global variables. */
|
||||
FPU_st0_tag = FPU_st0_ptr->tag;
|
||||
break;
|
||||
case _PUSH_:
|
||||
{
|
||||
pop_ptr = &st(-1);
|
||||
if ( pop_ptr->tag != TW_Empty )
|
||||
{ stack_overflow(); return; }
|
||||
top--;
|
||||
}
|
||||
break;
|
||||
case _null_:
|
||||
FPU_illegal();
|
||||
return;
|
||||
#ifdef PARANOID
|
||||
default:
|
||||
EXCEPTION(EX_INTERNAL);
|
||||
return;
|
||||
#endif PARANOID
|
||||
}
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case 000: /* fld m32real */
|
||||
clear_C1();
|
||||
reg_load_single(override);
|
||||
if ( (FPU_loaded_data.tag == TW_NaN) &&
|
||||
real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
|
||||
{
|
||||
top++;
|
||||
break;
|
||||
}
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 001: /* fild m32int */
|
||||
clear_C1();
|
||||
reg_load_int32(override);
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 002: /* fld m64real */
|
||||
clear_C1();
|
||||
reg_load_double(override);
|
||||
if ( (FPU_loaded_data.tag == TW_NaN) &&
|
||||
real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
|
||||
{
|
||||
top++;
|
||||
break;
|
||||
}
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 003: /* fild m16int */
|
||||
clear_C1();
|
||||
reg_load_int16(override);
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 010: /* fst m32real */
|
||||
clear_C1();
|
||||
reg_store_single(override);
|
||||
break;
|
||||
case 011: /* fist m32int */
|
||||
clear_C1();
|
||||
reg_store_int32(override);
|
||||
break;
|
||||
case 012: /* fst m64real */
|
||||
clear_C1();
|
||||
reg_store_double(override);
|
||||
break;
|
||||
case 013: /* fist m16int */
|
||||
clear_C1();
|
||||
reg_store_int16(override);
|
||||
break;
|
||||
case 014: /* fstp m32real */
|
||||
clear_C1();
|
||||
if ( reg_store_single(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
case 015: /* fistp m32int */
|
||||
clear_C1();
|
||||
if ( reg_store_int32(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
case 016: /* fstp m64real */
|
||||
clear_C1();
|
||||
if ( reg_store_double(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
case 017: /* fistp m16int */
|
||||
clear_C1();
|
||||
if ( reg_store_int16(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
case 020: /* fldenv m14/28byte */
|
||||
fldenv();
|
||||
break;
|
||||
case 022: /* frstor m94/108byte */
|
||||
frstor();
|
||||
break;
|
||||
case 023: /* fbld m80dec */
|
||||
clear_C1();
|
||||
reg_load_bcd(override);
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 024: /* fldcw */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_verify_area(VERIFY_READ, FPU_data_address, 2);
|
||||
control_word = get_fs_word((unsigned short *) FPU_data_address);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
if ( partial_status & ~control_word & CW_Exceptions )
|
||||
partial_status |= (SW_Summary | SW_Backward);
|
||||
else
|
||||
partial_status &= ~(SW_Summary | SW_Backward);
|
||||
#ifdef PECULIAR_486
|
||||
control_word |= 0x40; /* An 80486 appears to always set this bit */
|
||||
#endif PECULIAR_486
|
||||
NO_NET_DATA_EFFECT;
|
||||
NO_NET_INSTR_EFFECT;
|
||||
break;
|
||||
case 025: /* fld m80real */
|
||||
clear_C1();
|
||||
reg_load_extended(override);
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 027: /* fild m64int */
|
||||
clear_C1();
|
||||
reg_load_int64(override);
|
||||
reg_move(&FPU_loaded_data, pop_ptr);
|
||||
break;
|
||||
case 030: /* fstenv m14/28byte */
|
||||
fstenv();
|
||||
NO_NET_DATA_EFFECT;
|
||||
break;
|
||||
case 032: /* fsave */
|
||||
fsave();
|
||||
NO_NET_DATA_EFFECT;
|
||||
break;
|
||||
case 033: /* fbstp m80dec */
|
||||
clear_C1();
|
||||
if ( reg_store_bcd(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
case 034: /* fstcw m16int */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
|
||||
put_fs_word(control_word, (short *) FPU_data_address);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
NO_NET_DATA_EFFECT;
|
||||
NO_NET_INSTR_EFFECT;
|
||||
break;
|
||||
case 035: /* fstp m80real */
|
||||
clear_C1();
|
||||
if ( reg_store_extended(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
case 036: /* fstsw m2byte */
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
|
||||
put_fs_word(status_word(),(short *) FPU_data_address);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
NO_NET_DATA_EFFECT;
|
||||
NO_NET_INSTR_EFFECT;
|
||||
break;
|
||||
case 037: /* fistp m64int */
|
||||
clear_C1();
|
||||
if ( reg_store_int64(override) )
|
||||
pop_0(); /* pop only if the number was actually stored
|
||||
(see the 80486 manual p16-28) */
|
||||
break;
|
||||
}
|
||||
}
|
85
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_2xm1.c
Normal file
85
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_2xm1.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| poly_2xm1.c |
|
||||
| |
|
||||
| Function to compute 2^x-1 by a polynomial approximation. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
|
||||
|
||||
|
||||
#define HIPOWER 13
|
||||
static unsigned short const lterms[HIPOWER][4] =
|
||||
{
|
||||
{ 0x79b5, 0xd1cf, 0x17f7, 0xb172 },
|
||||
{ 0x1b56, 0x058b, 0x7bff, 0x3d7f },
|
||||
{ 0x8bb0, 0x8250, 0x846b, 0x0e35 },
|
||||
{ 0xbc65, 0xf747, 0x556d, 0x0276 },
|
||||
{ 0x17cb, 0x9e39, 0x61ff, 0x0057 },
|
||||
{ 0xe018, 0x9776, 0x1848, 0x000a },
|
||||
{ 0x66f2, 0xff30, 0xffe5, 0x0000 },
|
||||
{ 0x682f, 0xffb6, 0x162b, 0x0000 },
|
||||
{ 0xb7ca, 0x2956, 0x01b5, 0x0000 },
|
||||
{ 0xcd3e, 0x4817, 0x001e, 0x0000 },
|
||||
{ 0xb7e2, 0xecbe, 0x0001, 0x0000 },
|
||||
{ 0x0ed5, 0x1a27, 0x0000, 0x0000 },
|
||||
{ 0x101d, 0x0222, 0x0000, 0x0000 },
|
||||
};
|
||||
|
||||
|
||||
/*--- poly_2xm1() -----------------------------------------------------------+
|
||||
| Requires a positive argument which is TW_Valid and < 1. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
int poly_2xm1(FPU_REG const *arg, FPU_REG *result)
|
||||
{
|
||||
short exponent;
|
||||
long long Xll;
|
||||
FPU_REG accum;
|
||||
|
||||
|
||||
exponent = arg->exp - EXP_BIAS;
|
||||
|
||||
#ifdef PARANOID
|
||||
if ( (arg->sign != SIGN_POS) /* Can't hack a number < 0.0 */
|
||||
|| (exponent >= 0) /* or a |number| >= 1.0 */
|
||||
|| (arg->tag != TW_Valid) )
|
||||
{
|
||||
/* Number negative, too large, or not Valid. */
|
||||
EXCEPTION(EX_INTERNAL|0x127);
|
||||
return 1;
|
||||
}
|
||||
#endif PARANOID
|
||||
|
||||
*(unsigned *)&Xll = arg->sigl;
|
||||
*(((unsigned *)&Xll)+1) = arg->sigh;
|
||||
if ( exponent < -1 )
|
||||
{
|
||||
/* Shift the argument right by the required places. */
|
||||
if ( shrx(&Xll, -1-exponent) >= 0x80000000U )
|
||||
Xll++; /* round up */
|
||||
}
|
||||
|
||||
*(short *)&(accum.sign) = 0; /* Will be a valid positive nr with expon = 0 */
|
||||
accum.exp = 0;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial((unsigned *)&accum.sigl, (unsigned *)&Xll, lterms, HIPOWER-1);
|
||||
|
||||
/* Convert to 64 bit signed-compatible */
|
||||
accum.exp += EXP_BIAS - 1;
|
||||
|
||||
reg_move(&accum, result);
|
||||
|
||||
normalize(result);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
204
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_atan.c
Normal file
204
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_atan.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| p_atan.c |
|
||||
| |
|
||||
| Compute the tan of a FPU_REG, using a polynomial approximation. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
#define HIPOWERon 6 /* odd poly, negative terms */
|
||||
static unsigned const oddnegterms[HIPOWERon][2] =
|
||||
{
|
||||
{ 0x00000000, 0x00000000 }, /* for + 1.0 */
|
||||
{ 0x763b6f3d, 0x1adc4428 },
|
||||
{ 0x20f0630b, 0x0502909d },
|
||||
{ 0x4e825578, 0x0198ce38 },
|
||||
{ 0x22b7cb87, 0x008da6e3 },
|
||||
{ 0x9b30ca03, 0x00239c79 }
|
||||
} ;
|
||||
|
||||
#define HIPOWERop 6 /* odd poly, positive terms */
|
||||
static unsigned const oddplterms[HIPOWERop][2] =
|
||||
{
|
||||
{ 0xa6f67cb8, 0x94d910bd },
|
||||
{ 0xa02ffab4, 0x0a43cb45 },
|
||||
{ 0x04265e6b, 0x02bf5655 },
|
||||
{ 0x0a728914, 0x00f280f7 },
|
||||
{ 0x6d640e01, 0x004d6556 },
|
||||
{ 0xf1dd2dbf, 0x000a530a }
|
||||
};
|
||||
|
||||
static unsigned long long const denomterm = 0xea2e6612fc4bd208LL;
|
||||
|
||||
|
||||
/*--- poly_atan() -----------------------------------------------------------+
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
void poly_atan(FPU_REG *arg)
|
||||
{
|
||||
char recursions = 0;
|
||||
short exponent;
|
||||
FPU_REG odd_poly, even_poly, pos_poly, neg_poly, ratio;
|
||||
FPU_REG argSq;
|
||||
unsigned long long arg_signif, argSqSq;
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */
|
||||
{ arith_invalid(arg); return; } /* Need a positive number */
|
||||
#endif PARANOID
|
||||
|
||||
exponent = arg->exp - EXP_BIAS;
|
||||
|
||||
if ( arg->tag == TW_Zero )
|
||||
{
|
||||
/* Return 0.0 */
|
||||
reg_move(&CONST_Z, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( exponent >= -2 )
|
||||
{
|
||||
/* argument is in the range [0.25 .. 1.0] */
|
||||
if ( exponent >= 0 )
|
||||
{
|
||||
#ifdef PARANOID
|
||||
if ( (exponent == 0) &&
|
||||
(arg->sigl == 0) && (arg->sigh == 0x80000000) )
|
||||
#endif PARANOID
|
||||
{
|
||||
reg_move(&CONST_PI4, arg);
|
||||
return;
|
||||
}
|
||||
#ifdef PARANOID
|
||||
EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */
|
||||
return;
|
||||
#endif PARANOID
|
||||
}
|
||||
|
||||
/* If the argument is greater than sqrt(2)-1 (=0.414213562...) */
|
||||
/* convert the argument by an identity for atan */
|
||||
if ( (exponent >= -1) || (arg->sigh > 0xd413ccd0) )
|
||||
{
|
||||
FPU_REG numerator, denom;
|
||||
|
||||
recursions++;
|
||||
|
||||
arg_signif = significand(arg);
|
||||
if ( exponent < -1 )
|
||||
{
|
||||
if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U )
|
||||
arg_signif++; /* round up */
|
||||
}
|
||||
significand(&numerator) = -arg_signif;
|
||||
numerator.exp = EXP_BIAS - 1;
|
||||
normalize(&numerator); /* 1 - arg */
|
||||
|
||||
arg_signif = significand(arg);
|
||||
if ( shrx(&arg_signif, -exponent) >= 0x80000000U )
|
||||
arg_signif++; /* round up */
|
||||
significand(&denom) = arg_signif;
|
||||
denom.sigh |= 0x80000000; /* 1 + arg */
|
||||
|
||||
arg->exp = numerator.exp;
|
||||
reg_u_div(&numerator, &denom, arg, FULL_PRECISION);
|
||||
|
||||
exponent = arg->exp - EXP_BIAS;
|
||||
}
|
||||
}
|
||||
|
||||
arg_signif = significand(arg);
|
||||
|
||||
#ifdef PARANOID
|
||||
/* This must always be true */
|
||||
if ( exponent >= -1 )
|
||||
{
|
||||
EXCEPTION(EX_INTERNAL|0x120); /* There must be a logic error */
|
||||
}
|
||||
#endif PARANOID
|
||||
|
||||
/* shift the argument right by the required places */
|
||||
if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U )
|
||||
arg_signif++; /* round up */
|
||||
|
||||
/* Now have arg_signif with binary point at the left
|
||||
.1xxxxxxxx */
|
||||
mul64(&arg_signif, &arg_signif, &significand(&argSq));
|
||||
mul64(&significand(&argSq), &significand(&argSq), &argSqSq);
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(pos_poly.sign) = 0;
|
||||
pos_poly.exp = EXP_BIAS;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&pos_poly.sigl, (unsigned *)&argSqSq,
|
||||
(unsigned short (*)[4])oddplterms, HIPOWERop-1);
|
||||
mul64(&significand(&argSq), &significand(&pos_poly),
|
||||
&significand(&pos_poly));
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(neg_poly.sign) = 0;
|
||||
neg_poly.exp = EXP_BIAS;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&neg_poly.sigl, (unsigned *)&argSqSq,
|
||||
(unsigned short (*)[4])oddnegterms, HIPOWERon-1);
|
||||
|
||||
/* Subtract the mantissas */
|
||||
significand(&pos_poly) -= significand(&neg_poly);
|
||||
|
||||
reg_move(&pos_poly, &odd_poly);
|
||||
poly_add_1(&odd_poly);
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(even_poly.sign) = 0;
|
||||
|
||||
mul64(&significand(&argSq), &denomterm, &significand(&even_poly));
|
||||
|
||||
poly_add_1(&even_poly);
|
||||
|
||||
reg_div(&odd_poly, &even_poly, &ratio, FULL_PRECISION);
|
||||
|
||||
reg_u_mul(&ratio, arg, arg, FULL_PRECISION);
|
||||
|
||||
if ( recursions )
|
||||
reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* The argument to this function must be polynomial() compatible,
|
||||
i.e. have an exponent (not checked) of EXP_BIAS-1 but need not
|
||||
be normalized.
|
||||
This function adds 1.0 to the (assumed positive) argument. */
|
||||
void poly_add_1(FPU_REG *src)
|
||||
{
|
||||
/* Rounding in a consistent direction produces better results
|
||||
for the use of this function in poly_atan. Simple truncation
|
||||
is used here instead of round-to-nearest. */
|
||||
|
||||
#ifdef OBSOLETE
|
||||
char round = (src->sigl & 3) == 3;
|
||||
#endif OBSOLETE
|
||||
|
||||
shrx(&src->sigl, 1);
|
||||
|
||||
#ifdef OBSOLETE
|
||||
if ( round ) significand(src)++; /* Round to even */
|
||||
#endif OBSOLETE
|
||||
|
||||
src->sigh |= 0x80000000;
|
||||
|
||||
src->exp = EXP_BIAS;
|
||||
|
||||
}
|
97
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_div.S
Normal file
97
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_div.S
Normal file
|
@ -0,0 +1,97 @@
|
|||
.file "poly_div.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| poly_div.S |
|
||||
| |
|
||||
| A set of functions to divide 64 bit integers by fixed numbers. |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void poly_div2(unsigned long long *x) |
|
||||
| void poly_div4(unsigned long long *x) |
|
||||
| void poly_div16(unsigned long long *x) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_asm.h"
|
||||
|
||||
.text
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
.align 2,144
|
||||
.globl _poly_div2
|
||||
_poly_div2:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
|
||||
movl PARAM1,%ecx
|
||||
movw (%ecx),%ax
|
||||
|
||||
shrl $1,4(%ecx)
|
||||
rcrl $1,(%ecx)
|
||||
|
||||
testw $1,%ax
|
||||
je poly_div2_exit
|
||||
|
||||
addl $1,(%ecx)
|
||||
adcl $0,4(%ecx)
|
||||
poly_div2_exit:
|
||||
|
||||
leave
|
||||
ret
|
||||
/*---------------------------------------------------------------------------*/
|
||||
.align 2,144
|
||||
.globl _poly_div4
|
||||
_poly_div4:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
|
||||
movl PARAM1,%ecx
|
||||
movw (%ecx),%ax
|
||||
|
||||
movl 4(%ecx),%edx
|
||||
shll $30,%edx
|
||||
|
||||
shrl $2,4(%ecx)
|
||||
shrl $2,(%ecx)
|
||||
|
||||
orl %edx,(%ecx)
|
||||
|
||||
testw $2,%ax
|
||||
je poly_div4_exit
|
||||
|
||||
addl $1,(%ecx)
|
||||
adcl $0,4(%ecx)
|
||||
poly_div4_exit:
|
||||
|
||||
leave
|
||||
ret
|
||||
/*---------------------------------------------------------------------------*/
|
||||
.align 2,144
|
||||
.globl _poly_div16
|
||||
_poly_div16:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
|
||||
movl PARAM1,%ecx
|
||||
movw (%ecx),%ax
|
||||
|
||||
movl 4(%ecx),%edx
|
||||
shll $28,%edx
|
||||
|
||||
shrl $4,4(%ecx)
|
||||
shrl $4,(%ecx)
|
||||
|
||||
orl %edx,(%ecx)
|
||||
|
||||
testw $8,%ax
|
||||
je poly_div16_exit
|
||||
|
||||
addl $1,(%ecx)
|
||||
adcl $0,4(%ecx)
|
||||
poly_div16_exit:
|
||||
|
||||
leave
|
||||
ret
|
||||
/*---------------------------------------------------------------------------*/
|
289
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_l2.c
Normal file
289
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_l2.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| poly_l2.c |
|
||||
| |
|
||||
| Compute the base 2 log of a FPU_REG, using a polynomial approximation. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
|
||||
#define HIPOWER 9
|
||||
static unsigned short const lterms[HIPOWER][4] =
|
||||
{
|
||||
/* Ideal computation with these coeffs gives about
|
||||
64.6 bit rel accuracy. */
|
||||
{ 0xe177, 0xb82f, 0x7652, 0x7154 },
|
||||
{ 0xee0f, 0xe80f, 0x2770, 0x7b1c },
|
||||
{ 0x0fc0, 0xbe87, 0xb143, 0x49dd },
|
||||
{ 0x78b9, 0xdadd, 0xec54, 0x34c2 },
|
||||
{ 0x003a, 0x5de9, 0x628b, 0x2909 },
|
||||
{ 0x5588, 0xed16, 0x4abf, 0x2193 },
|
||||
{ 0xb461, 0x85f7, 0x347a, 0x1c6a },
|
||||
{ 0x0975, 0x87b3, 0xd5bf, 0x1876 },
|
||||
{ 0xe85c, 0xcec9, 0x84e7, 0x187d }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*--- poly_l2() -------------------------------------------------------------+
|
||||
| Base 2 logarithm by a polynomial approximation. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
void poly_l2(FPU_REG const *arg, FPU_REG *result)
|
||||
{
|
||||
short exponent;
|
||||
char zero; /* flag for an Xx == 0 */
|
||||
unsigned short bits, shift;
|
||||
unsigned long long Xsq;
|
||||
FPU_REG accum, denom, num, Xx;
|
||||
|
||||
|
||||
exponent = arg->exp - EXP_BIAS;
|
||||
|
||||
accum.tag = TW_Valid; /* set the tags to Valid */
|
||||
|
||||
if ( arg->sigh > (unsigned)0xb504f334 )
|
||||
{
|
||||
/* This is good enough for the computation of the polynomial
|
||||
sum, but actually results in a loss of precision for
|
||||
the computation of Xx. This will matter only if exponent
|
||||
becomes zero. */
|
||||
exponent++;
|
||||
accum.sign = 1; /* sign to negative */
|
||||
num.exp = EXP_BIAS; /* needed to prevent errors in div routine */
|
||||
reg_u_div(&CONST_1, arg, &num, FULL_PRECISION);
|
||||
}
|
||||
else
|
||||
{
|
||||
accum.sign = 0; /* set the sign to positive */
|
||||
num.sigl = arg->sigl; /* copy the mantissa */
|
||||
num.sigh = arg->sigh;
|
||||
}
|
||||
|
||||
|
||||
/* shift num left, lose the ms bit */
|
||||
num.sigh <<= 1;
|
||||
if ( num.sigl & 0x80000000 ) num.sigh |= 1;
|
||||
num.sigl <<= 1;
|
||||
|
||||
denom.sigl = num.sigl;
|
||||
denom.sigh = num.sigh;
|
||||
poly_div4(&significand(&denom));
|
||||
denom.sigh += 0x80000000; /* set the msb */
|
||||
Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */
|
||||
reg_u_div(&num, &denom, &Xx, FULL_PRECISION);
|
||||
|
||||
zero = !(Xx.sigh | Xx.sigl);
|
||||
|
||||
mul64(&significand(&Xx), &significand(&Xx), &Xsq);
|
||||
poly_div16(&Xsq);
|
||||
|
||||
accum.exp = -1; /* exponent of accum */
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial((unsigned *)&accum.sigl, (unsigned *)&Xsq, lterms, HIPOWER-1);
|
||||
|
||||
if ( !exponent )
|
||||
{
|
||||
/* If the exponent is zero, then we would lose precision by
|
||||
sticking to fixed point computation here */
|
||||
/* We need to re-compute Xx because of loss of precision. */
|
||||
FPU_REG lXx;
|
||||
char sign;
|
||||
|
||||
sign = accum.sign;
|
||||
accum.sign = 0;
|
||||
|
||||
/* make accum compatible and normalize */
|
||||
accum.exp = EXP_BIAS + accum.exp;
|
||||
normalize(&accum);
|
||||
|
||||
if ( zero )
|
||||
{
|
||||
reg_move(&CONST_Z, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we need to re-compute lXx to better accuracy */
|
||||
num.tag = TW_Valid; /* set the tags to Vaild */
|
||||
num.sign = 0; /* set the sign to positive */
|
||||
num.exp = EXP_BIAS - 1;
|
||||
if ( sign )
|
||||
{
|
||||
/* The argument is of the form 1-x */
|
||||
/* Use 1-1/(1-x) = x/(1-x) */
|
||||
significand(&num) = - significand(arg);
|
||||
normalize(&num);
|
||||
reg_div(&num, arg, &num, FULL_PRECISION);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalize(&num);
|
||||
}
|
||||
|
||||
denom.tag = TW_Valid; /* set the tags to Valid */
|
||||
denom.sign = SIGN_POS; /* set the sign to positive */
|
||||
denom.exp = EXP_BIAS;
|
||||
|
||||
reg_div(&num, &denom, &lXx, FULL_PRECISION);
|
||||
|
||||
reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION);
|
||||
|
||||
reg_u_add(&lXx, &accum, result, FULL_PRECISION);
|
||||
|
||||
normalize(result);
|
||||
}
|
||||
|
||||
result->sign = sign;
|
||||
return;
|
||||
}
|
||||
|
||||
mul64(&significand(&accum),
|
||||
&significand(&Xx), &significand(&accum));
|
||||
|
||||
significand(&accum) += significand(&Xx);
|
||||
|
||||
if ( Xx.sigh > accum.sigh )
|
||||
{
|
||||
/* There was an overflow */
|
||||
|
||||
poly_div2(&significand(&accum));
|
||||
accum.sigh |= 0x80000000;
|
||||
accum.exp++;
|
||||
}
|
||||
|
||||
/* When we add the exponent to the accum result later, we will
|
||||
require that their signs are the same. Here we ensure that
|
||||
this is so. */
|
||||
if ( exponent && ((exponent < 0) ^ (accum.sign)) )
|
||||
{
|
||||
/* signs are different */
|
||||
|
||||
accum.sign = !accum.sign;
|
||||
|
||||
/* An exceptional case is when accum is zero */
|
||||
if ( accum.sigl | accum.sigh )
|
||||
{
|
||||
/* find 1-accum */
|
||||
/* Shift to get exponent == 0 */
|
||||
if ( accum.exp < 0 )
|
||||
{
|
||||
poly_div2(&significand(&accum));
|
||||
accum.exp++;
|
||||
}
|
||||
/* Just negate, but throw away the sign */
|
||||
significand(&accum) = - significand(&accum);
|
||||
if ( exponent < 0 )
|
||||
exponent++;
|
||||
else
|
||||
exponent--;
|
||||
}
|
||||
}
|
||||
|
||||
shift = exponent >= 0 ? exponent : -exponent ;
|
||||
bits = 0;
|
||||
if ( shift )
|
||||
{
|
||||
if ( accum.exp )
|
||||
{
|
||||
accum.exp++;
|
||||
poly_div2(&significand(&accum));
|
||||
}
|
||||
while ( shift )
|
||||
{
|
||||
poly_div2(&significand(&accum));
|
||||
if ( shift & 1)
|
||||
accum.sigh |= 0x80000000;
|
||||
shift >>= 1;
|
||||
bits++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert to 64 bit signed-compatible */
|
||||
accum.exp += bits + EXP_BIAS - 1;
|
||||
|
||||
reg_move(&accum, result);
|
||||
normalize(result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*--- poly_l2p1() -----------------------------------------------------------+
|
||||
| Base 2 logarithm by a polynomial approximation. |
|
||||
| log2(x+1) |
|
||||
+---------------------------------------------------------------------------*/
|
||||
int poly_l2p1(FPU_REG const *arg, FPU_REG *result)
|
||||
{
|
||||
char sign = 0;
|
||||
unsigned long long Xsq;
|
||||
FPU_REG arg_pl1, denom, accum, local_arg, poly_arg;
|
||||
|
||||
|
||||
sign = arg->sign;
|
||||
|
||||
reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION);
|
||||
|
||||
if ( (arg_pl1.sign) | (arg_pl1.tag) )
|
||||
{ /* We need a valid positive number! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION);
|
||||
reg_div(arg, &denom, &local_arg, FULL_PRECISION);
|
||||
local_arg.sign = 0; /* Make the sign positive */
|
||||
|
||||
/* Now we need to check that |local_arg| is less than
|
||||
3-2*sqrt(2) = 0.17157.. = .0xafb0ccc0 * 2^-2 */
|
||||
|
||||
if ( local_arg.exp >= EXP_BIAS - 3 )
|
||||
{
|
||||
if ( (local_arg.exp > EXP_BIAS - 3) ||
|
||||
(local_arg.sigh > (unsigned)0xafb0ccc0) )
|
||||
{
|
||||
/* The argument is large */
|
||||
poly_l2(&arg_pl1, result); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a copy of local_arg */
|
||||
reg_move(&local_arg, &poly_arg);
|
||||
|
||||
/* Get poly_arg bits aligned as required */
|
||||
shrx((unsigned *)&(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3));
|
||||
|
||||
mul64(&significand(&poly_arg), &significand(&poly_arg), &Xsq);
|
||||
poly_div16(&Xsq);
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&(accum.sigl), (unsigned *)&Xsq, lterms, HIPOWER-1);
|
||||
|
||||
accum.tag = TW_Valid; /* set the tags to Valid */
|
||||
accum.sign = SIGN_POS; /* and make accum positive */
|
||||
|
||||
/* make accum compatible and normalize */
|
||||
accum.exp = EXP_BIAS - 1;
|
||||
normalize(&accum);
|
||||
|
||||
reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION);
|
||||
|
||||
reg_u_add(&local_arg, &accum, result, FULL_PRECISION);
|
||||
|
||||
/* Multiply the result by 2 */
|
||||
result->exp++;
|
||||
|
||||
result->sign = sign;
|
||||
|
||||
return 0;
|
||||
}
|
72
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_mul64.S
Normal file
72
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_mul64.S
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| poly_mul64.S |
|
||||
| |
|
||||
| Multiply two 64 bit integers. |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void mul64(long long *a, long long *b, long long *result) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "fpu_asm.h"
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
.globl _mul64
|
||||
_mul64:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
subl $16,%esp
|
||||
pushl %esi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi
|
||||
movl PARAM2,%ecx
|
||||
movl PARAM3,%ebx
|
||||
|
||||
xor %eax,%eax
|
||||
movl %eax,-4(%ebp)
|
||||
movl %eax,-8(%ebp)
|
||||
|
||||
movl (%esi),%eax
|
||||
mull (%ecx)
|
||||
movl %eax,-16(%ebp) /* Not used */
|
||||
movl %edx,-12(%ebp)
|
||||
|
||||
movl (%esi),%eax
|
||||
mull 4(%ecx)
|
||||
addl %eax,-12(%ebp)
|
||||
adcl %edx,-8(%ebp)
|
||||
adcl $0,-4(%ebp)
|
||||
|
||||
movl 4(%esi),%eax
|
||||
mull (%ecx)
|
||||
addl %eax,-12(%ebp)
|
||||
adcl %edx,-8(%ebp)
|
||||
adcl $0,-4(%ebp)
|
||||
|
||||
movl 4(%esi),%eax
|
||||
mull 4(%ecx)
|
||||
addl %eax,-8(%ebp)
|
||||
adcl %edx,-4(%ebp)
|
||||
|
||||
testb $128,-9(%ebp)
|
||||
je L_no_round
|
||||
|
||||
addl $1,-8(%ebp)
|
||||
adcl $0,-4(%ebp)
|
||||
|
||||
L_no_round:
|
||||
movl -8(%ebp),%esi
|
||||
movl %esi,(%ebx)
|
||||
movl -4(%ebp),%esi
|
||||
movl %esi,4(%ebx)
|
||||
|
||||
popl %ebx
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
150
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_sin.c
Normal file
150
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_sin.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| poly_sin.c |
|
||||
| |
|
||||
| Computation of an approximation of the sin function by a polynomial |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
#define HIPOWER 5
|
||||
static unsigned short const lterms[HIPOWER][4] =
|
||||
{
|
||||
{ 0x846a, 0x42d1, 0xb544, 0x921f},
|
||||
{ 0xe110, 0x75aa, 0xbc67, 0x1466},
|
||||
{ 0x503d, 0xa43f, 0x83c1, 0x000a},
|
||||
{ 0x8f9d, 0x7a19, 0x00f4, 0x0000},
|
||||
{ 0xda03, 0x06aa, 0x0000, 0x0000},
|
||||
};
|
||||
|
||||
static unsigned short const negterms[HIPOWER][4] =
|
||||
{
|
||||
{ 0x95ed, 0x2df2, 0xe731, 0xa55d},
|
||||
{ 0xd159, 0xe62b, 0xd2cc, 0x0132},
|
||||
{ 0x6342, 0xe9fb, 0x3c60, 0x0000},
|
||||
{ 0x6256, 0xdf5a, 0x0002, 0x0000},
|
||||
{ 0xf279, 0x000b, 0x0000, 0x0000},
|
||||
};
|
||||
|
||||
|
||||
/*--- poly_sine() -----------------------------------------------------------+
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
void poly_sine(FPU_REG const *arg, FPU_REG *result)
|
||||
{
|
||||
short exponent;
|
||||
FPU_REG fixed_arg, arg_sqrd, arg_to_4, accum, negaccum;
|
||||
|
||||
|
||||
exponent = arg->exp - EXP_BIAS;
|
||||
|
||||
if ( arg->tag == TW_Zero )
|
||||
{
|
||||
/* Return 0.0 */
|
||||
reg_move(&CONST_Z, result);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PARANOID
|
||||
if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */
|
||||
{
|
||||
EXCEPTION(EX_Invalid);
|
||||
reg_move(&CONST_QNaN, result);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( exponent >= 0 ) /* Can't hack a number > 1.0 */
|
||||
{
|
||||
if ( (exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000) )
|
||||
{
|
||||
reg_move(&CONST_1, result);
|
||||
return;
|
||||
}
|
||||
EXCEPTION(EX_Invalid);
|
||||
reg_move(&CONST_QNaN, result);
|
||||
return;
|
||||
}
|
||||
#endif PARANOID
|
||||
|
||||
fixed_arg.sigl = arg->sigl;
|
||||
fixed_arg.sigh = arg->sigh;
|
||||
if ( exponent < -1 )
|
||||
{
|
||||
/* shift the argument right by the required places */
|
||||
if ( shrx(&(fixed_arg.sigl), -1-exponent) >= 0x80000000U )
|
||||
significand(&fixed_arg)++; /* round up */
|
||||
}
|
||||
|
||||
mul64(&significand(&fixed_arg), &significand(&fixed_arg),
|
||||
&significand(&arg_sqrd));
|
||||
mul64(&significand(&arg_sqrd), &significand(&arg_sqrd),
|
||||
&significand(&arg_to_4));
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(accum.sign) = 0;
|
||||
accum.exp = 0;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&(accum.sigl), &(arg_to_4.sigl), lterms, HIPOWER-1);
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(negaccum.sign) = 0;
|
||||
negaccum.exp = 0;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&(negaccum.sigl), &(arg_to_4.sigl), negterms, HIPOWER-1);
|
||||
mul64(&significand(&arg_sqrd), &significand(&negaccum),
|
||||
&significand(&negaccum));
|
||||
|
||||
/* Subtract the mantissas */
|
||||
significand(&accum) -= significand(&negaccum);
|
||||
|
||||
/* Convert to 64 bit signed-compatible */
|
||||
accum.exp = EXP_BIAS - 1 + accum.exp;
|
||||
|
||||
reg_move(&accum, result);
|
||||
|
||||
normalize(result);
|
||||
|
||||
reg_mul(result, arg, result, FULL_PRECISION);
|
||||
reg_u_add(result, arg, result, FULL_PRECISION);
|
||||
|
||||
if ( result->exp >= EXP_BIAS )
|
||||
{
|
||||
/* A small overflow may be possible... but an illegal result. */
|
||||
if ( (result->exp > EXP_BIAS) /* Larger or equal 2.0 */
|
||||
|| (result->sigl > 1) /* Larger than 1.0+msb */
|
||||
|| (result->sigh != 0x80000000) /* Much > 1.0 */
|
||||
)
|
||||
{
|
||||
#ifdef DEBUGGING
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
|
||||
result->sigh, result->sigl);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
#endif DEBUGGING
|
||||
EXCEPTION(EX_INTERNAL|0x103);
|
||||
}
|
||||
|
||||
#ifdef DEBUGGING
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
|
||||
printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
|
||||
result->sigh, result->sigl);
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
#endif DEBUGGING
|
||||
|
||||
result->sigl = 0; /* Truncate the result to 1.00 */
|
||||
}
|
||||
|
||||
}
|
149
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_tan.c
Normal file
149
source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_tan.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| poly_tan.c |
|
||||
| |
|
||||
| Compute the tan of a FPU_REG, using a polynomial approximation. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
#define HIPOWERop 3 /* odd poly, positive terms */
|
||||
static unsigned short const oddplterms[HIPOWERop][4] =
|
||||
{
|
||||
{ 0x846a, 0x42d1, 0xb544, 0x921f},
|
||||
{ 0x6fb2, 0x0215, 0x95c0, 0x099c},
|
||||
{ 0xfce6, 0x0cc8, 0x1c9a, 0x0000}
|
||||
};
|
||||
|
||||
#define HIPOWERon 2 /* odd poly, negative terms */
|
||||
static unsigned short const oddnegterms[HIPOWERon][4] =
|
||||
{
|
||||
{ 0x6906, 0xe205, 0x25c8, 0x8838},
|
||||
{ 0x1dd7, 0x3fe3, 0x944e, 0x002c}
|
||||
};
|
||||
|
||||
#define HIPOWERep 2 /* even poly, positive terms */
|
||||
static unsigned short const evenplterms[HIPOWERep][4] =
|
||||
{
|
||||
{ 0xdb8f, 0x3761, 0x1432, 0x2acf},
|
||||
{ 0x16eb, 0x13c1, 0x3099, 0x0003}
|
||||
};
|
||||
|
||||
#define HIPOWERen 2 /* even poly, negative terms */
|
||||
static unsigned short const evennegterms[HIPOWERen][4] =
|
||||
{
|
||||
{ 0x3a7c, 0xe4c5, 0x7f87, 0x2945},
|
||||
{ 0x572b, 0x664c, 0xc543, 0x018c}
|
||||
};
|
||||
|
||||
|
||||
/*--- poly_tan() ------------------------------------------------------------+
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
void poly_tan(FPU_REG const *arg, FPU_REG *result, int invert)
|
||||
{
|
||||
short exponent;
|
||||
FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
|
||||
FPU_REG argSq;
|
||||
unsigned long long arg_signif, argSqSq;
|
||||
|
||||
|
||||
exponent = arg->exp - EXP_BIAS;
|
||||
|
||||
#ifdef PARANOID
|
||||
if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */
|
||||
{ arith_invalid(result); return; } /* Need a positive number */
|
||||
#endif PARANOID
|
||||
|
||||
arg_signif = significand(arg);
|
||||
if ( exponent < -1 )
|
||||
{
|
||||
/* shift the argument right by the required places */
|
||||
if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U )
|
||||
arg_signif++; /* round up */
|
||||
}
|
||||
|
||||
mul64(&arg_signif, &arg_signif, &significand(&argSq));
|
||||
mul64(&significand(&argSq), &significand(&argSq), &argSqSq);
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(pos_poly.sign) = 0;
|
||||
pos_poly.exp = EXP_BIAS;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&pos_poly.sigl, (unsigned *)&argSqSq, oddplterms, HIPOWERop-1);
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(neg_poly.sign) = 0;
|
||||
neg_poly.exp = EXP_BIAS;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, oddnegterms, HIPOWERon-1);
|
||||
mul64(&significand(&argSq), &significand(&neg_poly),
|
||||
&significand(&neg_poly));
|
||||
|
||||
/* Subtract the mantissas */
|
||||
significand(&pos_poly) -= significand(&neg_poly);
|
||||
|
||||
/* Convert to 64 bit signed-compatible */
|
||||
pos_poly.exp -= 1;
|
||||
|
||||
reg_move(&pos_poly, &odd_poly);
|
||||
normalize(&odd_poly);
|
||||
|
||||
reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
|
||||
/* Complete the odd polynomial. */
|
||||
reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION);
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(pos_poly.sign) = 0;
|
||||
pos_poly.exp = EXP_BIAS;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&pos_poly.sigl, (unsigned *)&argSqSq, evenplterms, HIPOWERep-1);
|
||||
mul64(&significand(&argSq),
|
||||
&significand(&pos_poly), &significand(&pos_poly));
|
||||
|
||||
/* will be a valid positive nr with expon = 0 */
|
||||
*(short *)&(neg_poly.sign) = 0;
|
||||
neg_poly.exp = EXP_BIAS;
|
||||
|
||||
/* Do the basic fixed point polynomial evaluation */
|
||||
polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, evennegterms, HIPOWERen-1);
|
||||
|
||||
/* Subtract the mantissas */
|
||||
significand(&neg_poly) -= significand(&pos_poly);
|
||||
/* and multiply by argSq */
|
||||
|
||||
/* Convert argSq to a valid reg number */
|
||||
*(short *)&(argSq.sign) = 0;
|
||||
argSq.exp = EXP_BIAS - 1;
|
||||
normalize(&argSq);
|
||||
|
||||
/* Convert to 64 bit signed-compatible */
|
||||
neg_poly.exp -= 1;
|
||||
|
||||
reg_move(&neg_poly, &even_poly);
|
||||
normalize(&even_poly);
|
||||
|
||||
reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
|
||||
reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
|
||||
/* Complete the even polynomial */
|
||||
reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION);
|
||||
|
||||
/* Now ready to copy the results */
|
||||
if ( invert )
|
||||
{ reg_div(&even_poly, &odd_poly, result, FULL_PRECISION); }
|
||||
else
|
||||
{ reg_div(&odd_poly, &even_poly, result, FULL_PRECISION); }
|
||||
|
||||
}
|
141
source/THIRDPARTY/linux-old/drivers/FPU-emu/polynomial.S
Normal file
141
source/THIRDPARTY/linux-old/drivers/FPU-emu/polynomial.S
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| polynomial.S |
|
||||
| |
|
||||
| Fixed point arithmetic polynomial evaluation. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2], |
|
||||
| int n) |
|
||||
| |
|
||||
| Computes: |
|
||||
| terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x |
|
||||
| The result is returned in accum. |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
.file "fpolynom.s"
|
||||
|
||||
#include "fpu_asm.h"
|
||||
|
||||
|
||||
/* #define EXTRA_PRECISE // Do not use: not complete */
|
||||
|
||||
#define TERM_SIZE $8
|
||||
#define SUM_MS -20(%ebp) /* sum ms long */
|
||||
#define SUM_MIDDLE -24(%ebp) /* sum middle long */
|
||||
#define SUM_LS -28(%ebp) /* sum ls long */
|
||||
#define SUM_LS_HI -25(%ebp) /* high byte of sum ls */
|
||||
#define ACCUM_MS -4(%ebp) /* accum ms long */
|
||||
#define ACCUM_MIDDLE -8(%ebp) /* accum middle long */
|
||||
#define ACCUM_LS -12(%ebp) /* accum ls long */
|
||||
#define ACCUM_LS_HI -9(%ebp) /* high byte of accum ls */
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
.globl _polynomial
|
||||
_polynomial:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
subl $32,%esp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM2,%esi /* x */
|
||||
movl PARAM3,%edi /* terms */
|
||||
|
||||
movl TERM_SIZE,%eax
|
||||
mull PARAM4 /* n */
|
||||
addl %eax,%edi
|
||||
|
||||
movl 4(%edi),%edx /* terms[n] */
|
||||
movl %edx,SUM_MS
|
||||
movl (%edi),%edx /* terms[n] */
|
||||
movl %edx,SUM_MIDDLE
|
||||
xor %eax,%eax
|
||||
movl %eax,SUM_LS
|
||||
|
||||
subl TERM_SIZE,%edi
|
||||
decl PARAM4
|
||||
js L_accum_done
|
||||
|
||||
L_accum_loop:
|
||||
xor %eax,%eax
|
||||
movl %eax,ACCUM_MS
|
||||
movl %eax,ACCUM_MIDDLE
|
||||
|
||||
movl SUM_MIDDLE,%eax
|
||||
mull (%esi) /* x ls long */
|
||||
/* movl %eax,-16(%ebp) // Not needed */
|
||||
movl %edx,ACCUM_LS
|
||||
|
||||
movl SUM_MIDDLE,%eax
|
||||
mull 4(%esi) /* x ms long */
|
||||
addl %eax,ACCUM_LS
|
||||
adcl %edx,ACCUM_MIDDLE
|
||||
adcl $0,ACCUM_MS
|
||||
|
||||
movl SUM_MS,%eax
|
||||
mull (%esi) /* x ls long */
|
||||
addl %eax,ACCUM_LS
|
||||
adcl %edx,ACCUM_MIDDLE
|
||||
adcl $0,ACCUM_MS
|
||||
|
||||
movl SUM_MS,%eax
|
||||
mull 4(%esi) /* x ms long */
|
||||
addl %eax,ACCUM_MIDDLE
|
||||
adcl %edx,ACCUM_MS
|
||||
|
||||
/*
|
||||
* Now put the sum of next term and the accumulator
|
||||
* into the sum register
|
||||
*/
|
||||
movl ACCUM_MIDDLE,%eax
|
||||
addl (%edi),%eax /* term ls long */
|
||||
movl %eax,SUM_MIDDLE
|
||||
movl ACCUM_MS,%eax
|
||||
adcl 4(%edi),%eax /* term ms long */
|
||||
movl %eax,SUM_MS
|
||||
|
||||
#ifdef EXTRA_PRECISE
|
||||
movl ACCUM_LS,%eax
|
||||
movl %eax,SUM_LS
|
||||
#else
|
||||
testb $0x80,ACCUM_LS_HI /* ms bit of ACCUM_LS */
|
||||
je L_no_poly_round
|
||||
|
||||
addl $1,SUM_MIDDLE
|
||||
adcl $0,SUM_MS
|
||||
L_no_poly_round:
|
||||
#endif EXTRA_PRECISE
|
||||
|
||||
subl TERM_SIZE,%edi
|
||||
decl PARAM4
|
||||
jns L_accum_loop
|
||||
|
||||
L_accum_done:
|
||||
#ifdef EXTRA_PRECISE
|
||||
/* Round the result */
|
||||
testb $128,SUM_LS_HI
|
||||
je L_poly_done
|
||||
|
||||
addl $1,SUM_MIDDLE
|
||||
adcl $0,SUM_MS
|
||||
#endif EXTRA_PRECISE
|
||||
|
||||
L_poly_done:
|
||||
movl PARAM1,%edi /* accum */
|
||||
movl SUM_MIDDLE,%eax
|
||||
movl %eax,(%edi)
|
||||
movl SUM_MS,%eax
|
||||
movl %eax,4(%edi)
|
||||
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
318
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_add_sub.c
Normal file
318
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_add_sub.c
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| reg_add_sub.c |
|
||||
| |
|
||||
| Functions to add or subtract two registers and put the result in a third. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| For each function, the destination may be any FPU_REG, including one of |
|
||||
| the source FPU_REGs. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
#include "fpu_system.h"
|
||||
|
||||
|
||||
int reg_add(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
|
||||
{
|
||||
char saved_sign = dest->sign;
|
||||
int diff;
|
||||
|
||||
if ( !(a->tag | b->tag) )
|
||||
{
|
||||
/* Both registers are valid */
|
||||
if (!(a->sign ^ b->sign))
|
||||
{
|
||||
/* signs are the same */
|
||||
dest->sign = a->sign;
|
||||
if ( reg_u_add(a, b, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The signs are different, so do a subtraction */
|
||||
diff = a->exp - b->exp;
|
||||
if (!diff)
|
||||
{
|
||||
diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
|
||||
if (!diff)
|
||||
{
|
||||
diff = a->sigl > b->sigl;
|
||||
if (!diff)
|
||||
diff = -(a->sigl < b->sigl);
|
||||
}
|
||||
}
|
||||
|
||||
if (diff > 0)
|
||||
{
|
||||
dest->sign = a->sign;
|
||||
if ( reg_u_sub(a, b, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ( diff == 0 )
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(&CONST_Z, dest);
|
||||
/* sign depends upon rounding mode */
|
||||
dest->sign = ((control_w & CW_RC) != RC_DOWN)
|
||||
? SIGN_POS : SIGN_NEG;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->sign = b->sign;
|
||||
if ( reg_u_sub(b, a, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
|
||||
{ return real_2op_NaN(a, b, dest); }
|
||||
else if (a->tag == TW_Zero)
|
||||
{
|
||||
if (b->tag == TW_Zero)
|
||||
{
|
||||
char different_signs = a->sign ^ b->sign;
|
||||
/* Both are zero, result will be zero. */
|
||||
reg_move(a, dest);
|
||||
if (different_signs)
|
||||
{
|
||||
/* Signs are different. */
|
||||
/* Sign of answer depends upon rounding mode. */
|
||||
dest->sign = ((control_w & CW_RC) != RC_DOWN)
|
||||
? SIGN_POS : SIGN_NEG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(b, dest);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (b->tag == TW_Zero)
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(a, dest); return 0;
|
||||
}
|
||||
else if (a->tag == TW_Infinity)
|
||||
{
|
||||
if (b->tag != TW_Infinity)
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(a, dest); return 0;
|
||||
}
|
||||
if (a->sign == b->sign)
|
||||
{
|
||||
/* They are both + or - infinity */
|
||||
reg_move(a, dest); return 0;
|
||||
}
|
||||
return arith_invalid(dest); /* Infinity-Infinity is undefined. */
|
||||
}
|
||||
else if (b->tag == TW_Infinity)
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(b, dest); return 0;
|
||||
}
|
||||
}
|
||||
#ifdef PARANOID
|
||||
EXCEPTION(EX_INTERNAL|0x101);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Subtract b from a. (a-b) -> dest */
|
||||
int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
|
||||
{
|
||||
char saved_sign = dest->sign;
|
||||
int diff;
|
||||
|
||||
if ( !(a->tag | b->tag) )
|
||||
{
|
||||
/* Both registers are valid */
|
||||
diff = a->exp - b->exp;
|
||||
if (!diff)
|
||||
{
|
||||
diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
|
||||
if (!diff)
|
||||
{
|
||||
diff = a->sigl > b->sigl;
|
||||
if (!diff)
|
||||
diff = -(a->sigl < b->sigl);
|
||||
}
|
||||
}
|
||||
|
||||
switch (a->sign*2 + b->sign)
|
||||
{
|
||||
case 0: /* P - P */
|
||||
case 3: /* N - N */
|
||||
if (diff > 0)
|
||||
{
|
||||
/* |a| > |b| */
|
||||
dest->sign = a->sign;
|
||||
if ( reg_u_sub(a, b, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if ( diff == 0 )
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(&CONST_Z, dest);
|
||||
/* sign depends upon rounding mode */
|
||||
dest->sign = ((control_w & CW_RC) != RC_DOWN)
|
||||
? SIGN_POS : SIGN_NEG;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
|
||||
if ( reg_u_sub(b, a, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: /* P - N */
|
||||
dest->sign = SIGN_POS;
|
||||
if ( reg_u_add(a, b, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 2: /* N - P */
|
||||
dest->sign = SIGN_NEG;
|
||||
if ( reg_u_add(a, b, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
|
||||
{ return real_2op_NaN(b, a, dest); }
|
||||
else if (b->tag == TW_Zero)
|
||||
{
|
||||
if (a->tag == TW_Zero)
|
||||
{
|
||||
char same_signs = !(a->sign ^ b->sign);
|
||||
/* Both are zero, result will be zero. */
|
||||
reg_move(a, dest); /* Answer for different signs. */
|
||||
if (same_signs)
|
||||
{
|
||||
/* Sign depends upon rounding mode */
|
||||
dest->sign = ((control_w & CW_RC) != RC_DOWN)
|
||||
? SIGN_POS : SIGN_NEG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(a, dest);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (a->tag == TW_Zero)
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(b, dest);
|
||||
dest->sign ^= SIGN_POS^SIGN_NEG;
|
||||
return 0;
|
||||
}
|
||||
else if (a->tag == TW_Infinity)
|
||||
{
|
||||
if (b->tag != TW_Infinity)
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(a, dest); return 0;
|
||||
}
|
||||
/* Both args are Infinity */
|
||||
if (a->sign == b->sign)
|
||||
{
|
||||
/* Infinity-Infinity is undefined. */
|
||||
return arith_invalid(dest);
|
||||
}
|
||||
reg_move(a, dest);
|
||||
return 0;
|
||||
}
|
||||
else if (b->tag == TW_Infinity)
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(b, dest);
|
||||
dest->sign ^= SIGN_POS^SIGN_NEG;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#ifdef PARANOID
|
||||
EXCEPTION(EX_INTERNAL|0x110);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
379
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_compare.c
Normal file
379
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_compare.c
Normal file
|
@ -0,0 +1,379 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| reg_compare.c |
|
||||
| |
|
||||
| Compare two floating point registers |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| compare() is the core FPU_REG comparison function |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
#include "status_w.h"
|
||||
|
||||
|
||||
int compare(FPU_REG const *b)
|
||||
{
|
||||
int diff;
|
||||
|
||||
if ( FPU_st0_ptr->tag | b->tag )
|
||||
{
|
||||
if ( FPU_st0_ptr->tag == TW_Zero )
|
||||
{
|
||||
if ( b->tag == TW_Zero ) return COMP_A_eq_B;
|
||||
if ( b->tag == TW_Valid )
|
||||
{
|
||||
return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
| ((b->exp <= EXP_UNDER) ?
|
||||
COMP_Denormal : 0)
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
}
|
||||
else if ( b->tag == TW_Zero )
|
||||
{
|
||||
if ( FPU_st0_ptr->tag == TW_Valid )
|
||||
{
|
||||
return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
|
||||
: COMP_A_lt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
| ((FPU_st0_ptr->exp <= EXP_UNDER )
|
||||
? COMP_Denormal : 0 )
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if ( FPU_st0_ptr->tag == TW_Infinity )
|
||||
{
|
||||
if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
|
||||
{
|
||||
return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
|
||||
: COMP_A_lt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
| (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
|
||||
COMP_Denormal : 0 )
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
else if ( b->tag == TW_Infinity )
|
||||
{
|
||||
/* The 80486 book says that infinities can be equal! */
|
||||
return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
|
||||
((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
||||
}
|
||||
/* Fall through to the NaN code */
|
||||
}
|
||||
else if ( b->tag == TW_Infinity )
|
||||
{
|
||||
if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
|
||||
{
|
||||
return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
| (((FPU_st0_ptr->tag == TW_Valid)
|
||||
&& (FPU_st0_ptr->exp <= EXP_UNDER)) ?
|
||||
COMP_Denormal : 0)
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
/* Fall through to the NaN code */
|
||||
}
|
||||
|
||||
/* The only possibility now should be that one of the arguments
|
||||
is a NaN */
|
||||
if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
|
||||
{
|
||||
if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
|
||||
|| ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
|
||||
/* At least one arg is a signaling NaN */
|
||||
return COMP_No_Comp | COMP_SNaN | COMP_NaN;
|
||||
else
|
||||
/* Neither is a signaling NaN */
|
||||
return COMP_No_Comp | COMP_NaN;
|
||||
}
|
||||
|
||||
EXCEPTION(EX_Invalid);
|
||||
}
|
||||
|
||||
#ifdef PARANOID
|
||||
if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
|
||||
if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
|
||||
#endif PARANOID
|
||||
|
||||
|
||||
if (FPU_st0_ptr->sign != b->sign)
|
||||
{
|
||||
return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
|
|
||||
( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
|
||||
COMP_Denormal : 0)
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
|
||||
diff = FPU_st0_ptr->exp - b->exp;
|
||||
if ( diff == 0 )
|
||||
{
|
||||
diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits are
|
||||
identical */
|
||||
if ( diff == 0 )
|
||||
{
|
||||
diff = FPU_st0_ptr->sigl > b->sigl;
|
||||
if ( diff == 0 )
|
||||
diff = -(FPU_st0_ptr->sigl < b->sigl);
|
||||
}
|
||||
}
|
||||
|
||||
if ( diff > 0 )
|
||||
{
|
||||
return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
|
|
||||
( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
|
||||
COMP_Denormal : 0)
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
if ( diff < 0 )
|
||||
{
|
||||
return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
||||
#ifdef DENORM_OPERAND
|
||||
|
|
||||
( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
|
||||
COMP_Denormal : 0)
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
}
|
||||
|
||||
return COMP_A_eq_B
|
||||
#ifdef DENORM_OPERAND
|
||||
|
|
||||
( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
|
||||
COMP_Denormal : 0)
|
||||
#endif DENORM_OPERAND
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This function requires that st(0) is not empty */
|
||||
int compare_st_data(void)
|
||||
{
|
||||
int f, c;
|
||||
|
||||
c = compare(&FPU_loaded_data);
|
||||
|
||||
if (c & COMP_NaN)
|
||||
{
|
||||
EXCEPTION(EX_Invalid);
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
}
|
||||
else
|
||||
switch (c & 7)
|
||||
{
|
||||
case COMP_A_lt_B:
|
||||
f = SW_C0;
|
||||
break;
|
||||
case COMP_A_eq_B:
|
||||
f = SW_C3;
|
||||
break;
|
||||
case COMP_A_gt_B:
|
||||
f = 0;
|
||||
break;
|
||||
case COMP_No_Comp:
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
break;
|
||||
#ifdef PARANOID
|
||||
default:
|
||||
EXCEPTION(EX_INTERNAL|0x121);
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
break;
|
||||
#endif PARANOID
|
||||
}
|
||||
setcc(f);
|
||||
if (c & COMP_Denormal)
|
||||
{
|
||||
return denormal_operand();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int compare_st_st(int nr)
|
||||
{
|
||||
int f, c;
|
||||
|
||||
if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
|
||||
{
|
||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||
/* Stack fault */
|
||||
EXCEPTION(EX_StackUnder);
|
||||
return !(control_word & CW_Invalid);
|
||||
}
|
||||
|
||||
c = compare(&st(nr));
|
||||
if (c & COMP_NaN)
|
||||
{
|
||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||
EXCEPTION(EX_Invalid);
|
||||
return !(control_word & CW_Invalid);
|
||||
}
|
||||
else
|
||||
switch (c & 7)
|
||||
{
|
||||
case COMP_A_lt_B:
|
||||
f = SW_C0;
|
||||
break;
|
||||
case COMP_A_eq_B:
|
||||
f = SW_C3;
|
||||
break;
|
||||
case COMP_A_gt_B:
|
||||
f = 0;
|
||||
break;
|
||||
case COMP_No_Comp:
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
break;
|
||||
#ifdef PARANOID
|
||||
default:
|
||||
EXCEPTION(EX_INTERNAL|0x122);
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
break;
|
||||
#endif PARANOID
|
||||
}
|
||||
setcc(f);
|
||||
if (c & COMP_Denormal)
|
||||
{
|
||||
return denormal_operand();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int compare_u_st_st(int nr)
|
||||
{
|
||||
int f, c;
|
||||
|
||||
if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
|
||||
{
|
||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||
/* Stack fault */
|
||||
EXCEPTION(EX_StackUnder);
|
||||
return !(control_word & CW_Invalid);
|
||||
}
|
||||
|
||||
c = compare(&st(nr));
|
||||
if (c & COMP_NaN)
|
||||
{
|
||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||
if (c & COMP_SNaN) /* This is the only difference between
|
||||
un-ordered and ordinary comparisons */
|
||||
{
|
||||
EXCEPTION(EX_Invalid);
|
||||
return !(control_word & CW_Invalid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
switch (c & 7)
|
||||
{
|
||||
case COMP_A_lt_B:
|
||||
f = SW_C0;
|
||||
break;
|
||||
case COMP_A_eq_B:
|
||||
f = SW_C3;
|
||||
break;
|
||||
case COMP_A_gt_B:
|
||||
f = 0;
|
||||
break;
|
||||
case COMP_No_Comp:
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
break;
|
||||
#ifdef PARANOID
|
||||
default:
|
||||
EXCEPTION(EX_INTERNAL|0x123);
|
||||
f = SW_C3 | SW_C2 | SW_C0;
|
||||
break;
|
||||
#endif PARANOID
|
||||
}
|
||||
setcc(f);
|
||||
if (c & COMP_Denormal)
|
||||
{
|
||||
return denormal_operand();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void fcom_st()
|
||||
{
|
||||
/* fcom st(i) */
|
||||
compare_st_st(FPU_rm);
|
||||
}
|
||||
|
||||
|
||||
void fcompst()
|
||||
{
|
||||
/* fcomp st(i) */
|
||||
if ( !compare_st_st(FPU_rm) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fcompp()
|
||||
{
|
||||
/* fcompp */
|
||||
if (FPU_rm != 1)
|
||||
{
|
||||
FPU_illegal();
|
||||
return;
|
||||
}
|
||||
if ( !compare_st_st(1) )
|
||||
{
|
||||
pop(); FPU_st0_ptr = &st(0);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fucom_()
|
||||
{
|
||||
/* fucom st(i) */
|
||||
compare_u_st_st(FPU_rm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fucomp()
|
||||
{
|
||||
/* fucomp st(i) */
|
||||
if ( !compare_u_st_st(FPU_rm) )
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
void fucompp()
|
||||
{
|
||||
/* fucompp */
|
||||
if (FPU_rm == 1)
|
||||
{
|
||||
if ( !compare_u_st_st(1) )
|
||||
{
|
||||
pop(); FPU_st0_ptr = &st(0);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
else
|
||||
FPU_illegal();
|
||||
}
|
116
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.c
Normal file
116
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| reg_constant.c |
|
||||
| |
|
||||
| All of the constant FPU_REGs |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_system.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "status_w.h"
|
||||
#include "reg_constant.h"
|
||||
|
||||
|
||||
FPU_REG const CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS,
|
||||
0x00000000, 0x80000000 };
|
||||
FPU_REG const CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1,
|
||||
0x00000000, 0x80000000 };
|
||||
FPU_REG const CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
|
||||
0x00000000, 0x80000000 };
|
||||
FPU_REG const CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1,
|
||||
0xcd1b8afe, 0xd49a784b };
|
||||
FPU_REG const CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS,
|
||||
0x5c17f0bc, 0xb8aa3b29 };
|
||||
FPU_REG const CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1,
|
||||
0x2168c235, 0xc90fdaa2 };
|
||||
FPU_REG const CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS,
|
||||
0x2168c235, 0xc90fdaa2 };
|
||||
FPU_REG const CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
|
||||
0x2168c235, 0xc90fdaa2 };
|
||||
FPU_REG const CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2,
|
||||
0xfbcff799, 0x9a209a84 };
|
||||
FPU_REG const CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
|
||||
0xd1cf79ac, 0xb17217f7 };
|
||||
|
||||
/* Extra bits to take pi/2 to more than 128 bits precision. */
|
||||
FPU_REG const CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66,
|
||||
0xfc8f8cbb, 0xece675d1 };
|
||||
|
||||
/* Only the sign (and tag) is used in internal zeroes */
|
||||
FPU_REG const CONST_Z = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 };
|
||||
|
||||
/* Only the sign and significand (and tag) are used in internal NaNs */
|
||||
/* The 80486 never generates one of these
|
||||
FPU_REG const CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
|
||||
*/
|
||||
/* This is the real indefinite QNaN */
|
||||
FPU_REG const CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
|
||||
|
||||
/* Only the sign (and tag) is used in internal infinities */
|
||||
FPU_REG const CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
|
||||
|
||||
|
||||
|
||||
static void fld_const(FPU_REG const *c)
|
||||
{
|
||||
FPU_REG *st_new_ptr;
|
||||
|
||||
if ( STACK_OVERFLOW )
|
||||
{
|
||||
stack_overflow();
|
||||
return;
|
||||
}
|
||||
push();
|
||||
reg_move(c, FPU_st0_ptr);
|
||||
clear_C1();
|
||||
}
|
||||
|
||||
|
||||
static void fld1(void)
|
||||
{
|
||||
fld_const(&CONST_1);
|
||||
}
|
||||
|
||||
static void fldl2t(void)
|
||||
{
|
||||
fld_const(&CONST_L2T);
|
||||
}
|
||||
|
||||
static void fldl2e(void)
|
||||
{
|
||||
fld_const(&CONST_L2E);
|
||||
}
|
||||
|
||||
static void fldpi(void)
|
||||
{
|
||||
fld_const(&CONST_PI);
|
||||
}
|
||||
|
||||
static void fldlg2(void)
|
||||
{
|
||||
fld_const(&CONST_LG2);
|
||||
}
|
||||
|
||||
static void fldln2(void)
|
||||
{
|
||||
fld_const(&CONST_LN2);
|
||||
}
|
||||
|
||||
static void fldz(void)
|
||||
{
|
||||
fld_const(&CONST_Z);
|
||||
}
|
||||
|
||||
static FUNC constants_table[] = {
|
||||
fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, FPU_illegal
|
||||
};
|
||||
|
||||
void fconst(void)
|
||||
{
|
||||
(constants_table[FPU_rm])();
|
||||
}
|
31
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.h
Normal file
31
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| reg_constant.h |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _REG_CONSTANT_H_
|
||||
#define _REG_CONSTANT_H_
|
||||
|
||||
#include "fpu_emu.h"
|
||||
|
||||
extern FPU_REG const CONST_1;
|
||||
extern FPU_REG const CONST_2;
|
||||
extern FPU_REG const CONST_HALF;
|
||||
extern FPU_REG const CONST_L2T;
|
||||
extern FPU_REG const CONST_L2E;
|
||||
extern FPU_REG const CONST_PI;
|
||||
extern FPU_REG const CONST_PI2;
|
||||
extern FPU_REG const CONST_PI2extra;
|
||||
extern FPU_REG const CONST_PI4;
|
||||
extern FPU_REG const CONST_LG2;
|
||||
extern FPU_REG const CONST_LN2;
|
||||
extern FPU_REG const CONST_Z;
|
||||
extern FPU_REG const CONST_PINF;
|
||||
extern FPU_REG const CONST_INF;
|
||||
extern FPU_REG const CONST_MINF;
|
||||
extern FPU_REG const CONST_QNaN;
|
||||
|
||||
#endif _REG_CONSTANT_H_
|
251
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_div.S
Normal file
251
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_div.S
Normal file
|
@ -0,0 +1,251 @@
|
|||
.file "reg_div.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| reg_div.S |
|
||||
| |
|
||||
| Divide one FPU_REG by another and put the result in a destination FPU_REG.|
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
|
||||
| unsigned int control_word) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
.globl _reg_div
|
||||
_reg_div:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
#ifdef REENTRANT_FPU
|
||||
subl $28,%esp /* Needed by divide_kernel */
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi
|
||||
movl PARAM2,%ebx
|
||||
movl PARAM3,%edi
|
||||
|
||||
movb TAG(%esi),%al
|
||||
orb TAG(%ebx),%al
|
||||
|
||||
jne L_div_special /* Not (both numbers TW_Valid) */
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
/* Check for denormals */
|
||||
cmpl EXP_UNDER,EXP(%esi)
|
||||
jg xL_arg1_not_denormal
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xL_arg1_not_denormal:
|
||||
cmpl EXP_UNDER,EXP(%ebx)
|
||||
jg xL_arg2_not_denormal
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xL_arg2_not_denormal:
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
/* Both arguments are TW_Valid */
|
||||
movb TW_Valid,TAG(%edi)
|
||||
|
||||
movb SIGN(%esi),%cl
|
||||
cmpb %cl,SIGN(%ebx)
|
||||
setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
|
||||
|
||||
movl EXP(%esi),%edx
|
||||
movl EXP(%ebx),%eax
|
||||
subl %eax,%edx
|
||||
addl EXP_BIAS,%edx
|
||||
movl %edx,EXP(%edi)
|
||||
|
||||
jmp _divide_kernel
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
L_div_special:
|
||||
cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
|
||||
je L_arg1_NaN
|
||||
|
||||
cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
|
||||
jne L_no_NaN_arg
|
||||
|
||||
/* Operations on NaNs */
|
||||
L_arg1_NaN:
|
||||
L_arg2_NaN:
|
||||
pushl %edi /* Destination */
|
||||
pushl %esi
|
||||
pushl %ebx /* Ordering is important here */
|
||||
call _real_2op_NaN
|
||||
jmp LDiv_exit
|
||||
|
||||
/* Invalid operations */
|
||||
L_zero_zero:
|
||||
L_inf_inf:
|
||||
pushl %edi /* Destination */
|
||||
call _arith_invalid /* 0/0 or Infinity/Infinity */
|
||||
jmp LDiv_exit
|
||||
|
||||
L_no_NaN_arg:
|
||||
cmpb TW_Infinity,TAG(%esi)
|
||||
jne L_arg1_not_inf
|
||||
|
||||
cmpb TW_Infinity,TAG(%ebx)
|
||||
je L_inf_inf /* invalid operation */
|
||||
|
||||
cmpb TW_Valid,TAG(%ebx)
|
||||
je L_inf_valid
|
||||
|
||||
#ifdef PARANOID
|
||||
/* arg2 must be zero or valid */
|
||||
cmpb TW_Zero,TAG(%ebx)
|
||||
ja L_unknown_tags
|
||||
#endif PARANOID
|
||||
|
||||
/* Note that p16-9 says that infinity/0 returns infinity */
|
||||
jmp L_copy_arg1 /* Answer is Inf */
|
||||
|
||||
L_inf_valid:
|
||||
#ifdef DENORM_OPERAND
|
||||
cmpl EXP_UNDER,EXP(%ebx)
|
||||
jg L_copy_arg1 /* Answer is Inf */
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
jmp L_copy_arg1 /* Answer is Inf */
|
||||
|
||||
L_arg1_not_inf:
|
||||
cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
|
||||
jne L_arg2_not_zero
|
||||
|
||||
cmpb TW_Zero,TAG(%esi)
|
||||
je L_zero_zero /* invalid operation */
|
||||
|
||||
#ifdef PARANOID
|
||||
/* arg1 must be valid */
|
||||
cmpb TW_Valid,TAG(%esi)
|
||||
ja L_unknown_tags
|
||||
#endif PARANOID
|
||||
|
||||
/* Division by zero error */
|
||||
pushl %edi /* destination */
|
||||
movb SIGN(%esi),%al
|
||||
xorb SIGN(%ebx),%al
|
||||
pushl %eax /* lower 8 bits have the sign */
|
||||
call _divide_by_zero
|
||||
jmp LDiv_exit
|
||||
|
||||
L_arg2_not_zero:
|
||||
cmpb TW_Infinity,TAG(%ebx)
|
||||
jne L_arg2_not_inf
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
cmpb TW_Valid,TAG(%esi)
|
||||
jne L_return_zero
|
||||
|
||||
cmpl EXP_UNDER,EXP(%esi)
|
||||
jg L_return_zero /* Answer is zero */
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
jmp L_return_zero /* Answer is zero */
|
||||
|
||||
L_arg2_not_inf:
|
||||
|
||||
#ifdef PARANOID
|
||||
cmpb TW_Zero,TAG(%esi)
|
||||
jne L_unknown_tags
|
||||
#endif PARANOID
|
||||
|
||||
/* arg1 is zero, arg2 is not Infinity or a NaN */
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
cmpl EXP_UNDER,EXP(%ebx)
|
||||
jg L_copy_arg1 /* Answer is zero */
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
L_copy_arg1:
|
||||
movb TAG(%esi),%ax
|
||||
movb %ax,TAG(%edi)
|
||||
movl EXP(%esi),%eax
|
||||
movl %eax,EXP(%edi)
|
||||
movl SIGL(%esi),%eax
|
||||
movl %eax,SIGL(%edi)
|
||||
movl SIGH(%esi),%eax
|
||||
movl %eax,SIGH(%edi)
|
||||
|
||||
LDiv_set_result_sign:
|
||||
movb SIGN(%esi),%cl
|
||||
cmpb %cl,SIGN(%ebx)
|
||||
jne LDiv_negative_result
|
||||
|
||||
movb SIGN_POS,SIGN(%edi)
|
||||
xorl %eax,%eax /* Valid result */
|
||||
jmp LDiv_exit
|
||||
|
||||
LDiv_negative_result:
|
||||
movb SIGN_NEG,SIGN(%edi)
|
||||
xorl %eax,%eax /* Valid result */
|
||||
|
||||
LDiv_exit:
|
||||
#ifdef REENTRANT_FPU
|
||||
leal -40(%ebp),%esp
|
||||
#else
|
||||
leal -12(%ebp),%esp
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
|
||||
L_return_zero:
|
||||
xorl %eax,%eax
|
||||
movl %eax,SIGH(%edi)
|
||||
movl %eax,SIGL(%edi)
|
||||
movl EXP_UNDER,EXP(%edi)
|
||||
movb TW_Zero,TAG(%edi)
|
||||
jmp LDiv_set_result_sign
|
||||
|
||||
#ifdef PARANOID
|
||||
L_unknown_tags:
|
||||
pushl EX_INTERNAL | 0x208
|
||||
call EXCEPTION
|
||||
|
||||
/* Generate a NaN for unknown tags */
|
||||
movl _CONST_QNaN,%eax
|
||||
movl %eax,(%edi)
|
||||
movl _CONST_QNaN+4,%eax
|
||||
movl %eax,SIGL(%edi)
|
||||
movl _CONST_QNaN+8,%eax
|
||||
movl %eax,SIGH(%edi)
|
||||
jmp LDiv_exit /* %eax is nz */
|
||||
#endif PARANOID
|
1402
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_ld_str.c
Normal file
1402
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_ld_str.c
Normal file
File diff suppressed because it is too large
Load diff
106
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_mul.c
Normal file
106
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_mul.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| reg_mul.c |
|
||||
| |
|
||||
| Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| The destination may be any FPU_REG, including one of the source FPU_REGs. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
|
||||
|
||||
/* This routine must be called with non-empty source registers */
|
||||
int reg_mul(FPU_REG const *a, FPU_REG const *b,
|
||||
FPU_REG *dest, unsigned int control_w)
|
||||
{
|
||||
char saved_sign = dest->sign;
|
||||
char sign = (a->sign ^ b->sign);
|
||||
|
||||
if (!(a->tag | b->tag))
|
||||
{
|
||||
/* Both regs Valid, this should be the most common case. */
|
||||
dest->sign = sign;
|
||||
if ( reg_u_mul(a, b, dest, control_w) )
|
||||
{
|
||||
dest->sign = saved_sign;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero))
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ||
|
||||
((a->tag == TW_Valid) && (a->exp <= EXP_UNDER)) )
|
||||
{
|
||||
if ( denormal_operand() ) return 1;
|
||||
}
|
||||
#endif DENORM_OPERAND
|
||||
/* Must have either both arguments == zero, or
|
||||
one valid and the other zero.
|
||||
The result is therefore zero. */
|
||||
reg_move(&CONST_Z, dest);
|
||||
#ifdef PECULIAR_486
|
||||
/* The 80486 book says that the answer is +0, but a real
|
||||
80486 appears to behave this way... */
|
||||
dest->sign = sign;
|
||||
#endif PECULIAR_486
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Must have infinities, NaNs, etc */
|
||||
if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
|
||||
{ return real_2op_NaN(a, b, dest); }
|
||||
else if (a->tag == TW_Infinity)
|
||||
{
|
||||
if (b->tag == TW_Zero)
|
||||
{ return arith_invalid(dest); } /* Zero*Infinity is invalid */
|
||||
else
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(a, dest);
|
||||
dest->sign = sign;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (b->tag == TW_Infinity)
|
||||
{
|
||||
if (a->tag == TW_Zero)
|
||||
{ return arith_invalid(dest); } /* Zero*Infinity is invalid */
|
||||
else
|
||||
{
|
||||
#ifdef DENORM_OPERAND
|
||||
if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
|
||||
denormal_operand() )
|
||||
return 1;
|
||||
#endif DENORM_OPERAND
|
||||
reg_move(b, dest);
|
||||
dest->sign = sign;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#ifdef PARANOID
|
||||
else
|
||||
{
|
||||
EXCEPTION(EX_INTERNAL|0x102);
|
||||
return 1;
|
||||
}
|
||||
#endif PARANOID
|
||||
}
|
||||
}
|
150
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_norm.S
Normal file
150
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_norm.S
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| reg_norm.S |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Normalize the value in a FPU_REG. |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void normalize(FPU_REG *n) |
|
||||
| |
|
||||
| void normalize_nuo(FPU_REG *n) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_asm.h"
|
||||
|
||||
|
||||
.text
|
||||
|
||||
.align 2,144
|
||||
.globl _normalize
|
||||
|
||||
_normalize:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%ebx
|
||||
|
||||
#ifdef PARANOID
|
||||
cmpb TW_Valid,TAG(%ebx)
|
||||
je L_ok
|
||||
|
||||
pushl $0x220
|
||||
call _exception
|
||||
addl $4,%esp
|
||||
|
||||
L_ok:
|
||||
#endif PARANOID
|
||||
|
||||
movl SIGH(%ebx),%edx
|
||||
movl SIGL(%ebx),%eax
|
||||
|
||||
orl %edx,%edx /* ms bits */
|
||||
js L_done /* Already normalized */
|
||||
jnz L_shift_1 /* Shift left 1 - 31 bits */
|
||||
|
||||
orl %eax,%eax
|
||||
jz L_zero /* The contents are zero */
|
||||
|
||||
movl %eax,%edx
|
||||
xorl %eax,%eax
|
||||
subl $32,EXP(%ebx) /* This can cause an underflow */
|
||||
|
||||
/* We need to shift left by 1 - 31 bits */
|
||||
L_shift_1:
|
||||
bsrl %edx,%ecx /* get the required shift in %ecx */
|
||||
subl $31,%ecx
|
||||
negl %ecx
|
||||
shld %cl,%eax,%edx
|
||||
shl %cl,%eax
|
||||
subl %ecx,EXP(%ebx) /* This can cause an underflow */
|
||||
|
||||
movl %edx,SIGH(%ebx)
|
||||
movl %eax,SIGL(%ebx)
|
||||
|
||||
L_done:
|
||||
cmpl EXP_OVER,EXP(%ebx)
|
||||
jge L_overflow
|
||||
|
||||
cmpl EXP_UNDER,EXP(%ebx)
|
||||
jle L_underflow
|
||||
|
||||
L_exit:
|
||||
popl %ebx
|
||||
leave
|
||||
ret
|
||||
|
||||
|
||||
L_zero:
|
||||
movl EXP_UNDER,EXP(%ebx)
|
||||
movb TW_Zero,TAG(%ebx)
|
||||
jmp L_exit
|
||||
|
||||
L_underflow:
|
||||
push %ebx
|
||||
call _arith_underflow
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
|
||||
L_overflow:
|
||||
push %ebx
|
||||
call _arith_overflow
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
|
||||
|
||||
|
||||
/* Normalise without reporting underflow or overflow */
|
||||
.align 2,144
|
||||
.globl _normalize_nuo
|
||||
|
||||
_normalize_nuo:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%ebx
|
||||
|
||||
#ifdef PARANOID
|
||||
cmpb TW_Valid,TAG(%ebx)
|
||||
je L_ok_nuo
|
||||
|
||||
pushl $0x221
|
||||
call _exception
|
||||
addl $4,%esp
|
||||
|
||||
L_ok_nuo:
|
||||
#endif PARANOID
|
||||
|
||||
movl SIGH(%ebx),%edx
|
||||
movl SIGL(%ebx),%eax
|
||||
|
||||
orl %edx,%edx /* ms bits */
|
||||
js L_exit /* Already normalized */
|
||||
jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
|
||||
|
||||
orl %eax,%eax
|
||||
jz L_zero /* The contents are zero */
|
||||
|
||||
movl %eax,%edx
|
||||
xorl %eax,%eax
|
||||
subl $32,EXP(%ebx) /* This can cause an underflow */
|
||||
|
||||
/* We need to shift left by 1 - 31 bits */
|
||||
L_nuo_shift_1:
|
||||
bsrl %edx,%ecx /* get the required shift in %ecx */
|
||||
subl $31,%ecx
|
||||
negl %ecx
|
||||
shld %cl,%eax,%edx
|
||||
shl %cl,%eax
|
||||
subl %ecx,EXP(%ebx) /* This can cause an underflow */
|
||||
|
||||
movl %edx,SIGH(%ebx)
|
||||
movl %eax,SIGL(%ebx)
|
||||
jmp L_exit
|
||||
|
||||
|
666
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_round.S
Normal file
666
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_round.S
Normal file
|
@ -0,0 +1,666 @@
|
|||
.file "reg_round.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| reg_round.S |
|
||||
| |
|
||||
| Rounding/truncation/etc for FPU basic arithmetic functions. |
|
||||
| |
|
||||
| Copyright (C) 1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| This code has four possible entry points. |
|
||||
| The following must be entered by a jmp intruction: |
|
||||
| fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. |
|
||||
| |
|
||||
| The _round_reg entry point is intended to be used by C code. |
|
||||
| From C, call as: |
|
||||
| void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
|
||||
| |
|
||||
| For correct "up" and "down" rounding, the argument must have the correct |
|
||||
| sign. |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Four entry points. |
|
||||
| |
|
||||
| Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: |
|
||||
| %eax:%ebx 64 bit significand |
|
||||
| %edx 32 bit extension of the significand |
|
||||
| %edi pointer to an FPU_REG for the result to be stored |
|
||||
| stack calling function must have set up a C stack frame and |
|
||||
| pushed %esi, %edi, and %ebx |
|
||||
| |
|
||||
| Needed just for the fpu_reg_round_sqrt entry point: |
|
||||
| %cx A control word in the same format as the FPU control word. |
|
||||
| Otherwise, PARAM4 must give such a value. |
|
||||
| |
|
||||
| |
|
||||
| The significand and its extension are assumed to be exact in the |
|
||||
| following sense: |
|
||||
| If the significand by itself is the exact result then the significand |
|
||||
| extension (%edx) must contain 0, otherwise the significand extension |
|
||||
| must be non-zero. |
|
||||
| If the significand extension is non-zero then the significand is |
|
||||
| smaller than the magnitude of the correct exact result by an amount |
|
||||
| greater than zero and less than one ls bit of the significand. |
|
||||
| The significand extension is only required to have three possible |
|
||||
| non-zero values: |
|
||||
| less than 0x80000000 <=> the significand is less than 1/2 an ls |
|
||||
| bit smaller than the magnitude of the |
|
||||
| true exact result. |
|
||||
| exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
|
||||
| smaller than the magnitude of the true |
|
||||
| exact result. |
|
||||
| greater than 0x80000000 <=> the significand is more than 1/2 an ls |
|
||||
| bit smaller than the magnitude of the |
|
||||
| true exact result. |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| The code in this module has become quite complex, but it should handle |
|
||||
| all of the FPU flags which are set at this stage of the basic arithmetic |
|
||||
| computations. |
|
||||
| There are a few rare cases where the results are not set identically to |
|
||||
| a real FPU. These require a bit more thought because at this stage the |
|
||||
| results of the code here appear to be more consistent... |
|
||||
| This may be changed in a future version. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "fpu_asm.h"
|
||||
#include "exception.h"
|
||||
#include "control_w.h"
|
||||
|
||||
/* Flags for FPU_bits_lost */
|
||||
#define LOST_DOWN $1
|
||||
#define LOST_UP $2
|
||||
|
||||
/* Flags for FPU_denormal */
|
||||
#define DENORMAL $1
|
||||
#define UNMASKED_UNDERFLOW $2
|
||||
|
||||
|
||||
#ifdef REENTRANT_FPU
|
||||
/* Make the code re-entrant by putting
|
||||
local storage on the stack: */
|
||||
#define FPU_bits_lost (%esp)
|
||||
#define FPU_denormal 1(%esp)
|
||||
|
||||
#else
|
||||
/* Not re-entrant, so we can gain speed by putting
|
||||
local storage in a static area: */
|
||||
.data
|
||||
.align 2,0
|
||||
FPU_bits_lost:
|
||||
.byte 0
|
||||
FPU_denormal:
|
||||
.byte 0
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
.globl fpu_reg_round
|
||||
.globl fpu_reg_round_sqrt
|
||||
.globl fpu_Arith_exit
|
||||
.globl _round_reg
|
||||
|
||||
/* Entry point when called from C */
|
||||
_round_reg:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%edi
|
||||
movl SIGH(%edi),%eax
|
||||
movl SIGL(%edi),%ebx
|
||||
movl PARAM2,%edx
|
||||
movl PARAM3,%ecx
|
||||
jmp fpu_reg_round_sqrt
|
||||
|
||||
fpu_reg_round: /* Normal entry point */
|
||||
movl PARAM4,%ecx
|
||||
|
||||
fpu_reg_round_sqrt: /* Entry point from wm_sqrt.S */
|
||||
|
||||
#ifdef REENTRANT_FPU
|
||||
pushl %ebx /* adjust the stack pointer */
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
#ifdef PARANOID
|
||||
/* Cannot use this here yet */
|
||||
/* orl %eax,%eax */
|
||||
/* jns L_entry_bugged */
|
||||
#endif PARANOID
|
||||
|
||||
cmpl EXP_UNDER,EXP(%edi)
|
||||
jle xMake_denorm /* The number is a de-normal */
|
||||
|
||||
movb $0,FPU_denormal /* 0 -> not a de-normal */
|
||||
|
||||
xDenorm_done:
|
||||
movb $0,FPU_bits_lost /* No bits yet lost in rounding */
|
||||
|
||||
movl %ecx,%esi
|
||||
andl CW_PC,%ecx
|
||||
cmpl PR_64_BITS,%ecx
|
||||
je LRound_To_64
|
||||
|
||||
cmpl PR_53_BITS,%ecx
|
||||
je LRound_To_53
|
||||
|
||||
cmpl PR_24_BITS,%ecx
|
||||
je LRound_To_24
|
||||
|
||||
#ifdef PARANOID
|
||||
jmp L_bugged /* There is no bug, just a bad control word */
|
||||
#endif PARANOID
|
||||
|
||||
|
||||
/* Round etc to 24 bit precision */
|
||||
LRound_To_24:
|
||||
movl %esi,%ecx
|
||||
andl CW_RC,%ecx
|
||||
cmpl RC_RND,%ecx
|
||||
je LRound_nearest_24
|
||||
|
||||
cmpl RC_CHOP,%ecx
|
||||
je LCheck_truncate_24
|
||||
|
||||
cmpl RC_UP,%ecx /* Towards +infinity */
|
||||
je LUp_24
|
||||
|
||||
cmpl RC_DOWN,%ecx /* Towards -infinity */
|
||||
je LDown_24
|
||||
|
||||
#ifdef PARANOID
|
||||
jmp L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
LUp_24:
|
||||
cmpb SIGN_POS,SIGN(%edi)
|
||||
jne LCheck_truncate_24 /* If negative then up==truncate */
|
||||
|
||||
jmp LCheck_24_round_up
|
||||
|
||||
LDown_24:
|
||||
cmpb SIGN_POS,SIGN(%edi)
|
||||
je LCheck_truncate_24 /* If positive then down==truncate */
|
||||
|
||||
LCheck_24_round_up:
|
||||
movl %eax,%ecx
|
||||
andl $0x000000ff,%ecx
|
||||
orl %ebx,%ecx
|
||||
orl %edx,%ecx
|
||||
jnz LDo_24_round_up
|
||||
jmp LRe_normalise
|
||||
|
||||
LRound_nearest_24:
|
||||
/* Do rounding of the 24th bit if needed (nearest or even) */
|
||||
movl %eax,%ecx
|
||||
andl $0x000000ff,%ecx
|
||||
cmpl $0x00000080,%ecx
|
||||
jc LCheck_truncate_24 /* less than half, no increment needed */
|
||||
|
||||
jne LGreater_Half_24 /* greater than half, increment needed */
|
||||
|
||||
/* Possibly half, we need to check the ls bits */
|
||||
orl %ebx,%ebx
|
||||
jnz LGreater_Half_24 /* greater than half, increment needed */
|
||||
|
||||
orl %edx,%edx
|
||||
jnz LGreater_Half_24 /* greater than half, increment needed */
|
||||
|
||||
/* Exactly half, increment only if 24th bit is 1 (round to even) */
|
||||
testl $0x00000100,%eax
|
||||
jz LDo_truncate_24
|
||||
|
||||
LGreater_Half_24: /* Rounding: increment at the 24th bit */
|
||||
LDo_24_round_up:
|
||||
andl $0xffffff00,%eax /* Truncate to 24 bits */
|
||||
xorl %ebx,%ebx
|
||||
movb LOST_UP,FPU_bits_lost
|
||||
addl $0x00000100,%eax
|
||||
jmp LCheck_Round_Overflow
|
||||
|
||||
LCheck_truncate_24:
|
||||
movl %eax,%ecx
|
||||
andl $0x000000ff,%ecx
|
||||
orl %ebx,%ecx
|
||||
orl %edx,%ecx
|
||||
jz LRe_normalise /* No truncation needed */
|
||||
|
||||
LDo_truncate_24:
|
||||
andl $0xffffff00,%eax /* Truncate to 24 bits */
|
||||
xorl %ebx,%ebx
|
||||
movb LOST_DOWN,FPU_bits_lost
|
||||
jmp LRe_normalise
|
||||
|
||||
|
||||
/* Round etc to 53 bit precision */
|
||||
LRound_To_53:
|
||||
movl %esi,%ecx
|
||||
andl CW_RC,%ecx
|
||||
cmpl RC_RND,%ecx
|
||||
je LRound_nearest_53
|
||||
|
||||
cmpl RC_CHOP,%ecx
|
||||
je LCheck_truncate_53
|
||||
|
||||
cmpl RC_UP,%ecx /* Towards +infinity */
|
||||
je LUp_53
|
||||
|
||||
cmpl RC_DOWN,%ecx /* Towards -infinity */
|
||||
je LDown_53
|
||||
|
||||
#ifdef PARANOID
|
||||
jmp L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
LUp_53:
|
||||
cmpb SIGN_POS,SIGN(%edi)
|
||||
jne LCheck_truncate_53 /* If negative then up==truncate */
|
||||
|
||||
jmp LCheck_53_round_up
|
||||
|
||||
LDown_53:
|
||||
cmpb SIGN_POS,SIGN(%edi)
|
||||
je LCheck_truncate_53 /* If positive then down==truncate */
|
||||
|
||||
LCheck_53_round_up:
|
||||
movl %ebx,%ecx
|
||||
andl $0x000007ff,%ecx
|
||||
orl %edx,%ecx
|
||||
jnz LDo_53_round_up
|
||||
jmp LRe_normalise
|
||||
|
||||
LRound_nearest_53:
|
||||
/* Do rounding of the 53rd bit if needed (nearest or even) */
|
||||
movl %ebx,%ecx
|
||||
andl $0x000007ff,%ecx
|
||||
cmpl $0x00000400,%ecx
|
||||
jc LCheck_truncate_53 /* less than half, no increment needed */
|
||||
|
||||
jnz LGreater_Half_53 /* greater than half, increment needed */
|
||||
|
||||
/* Possibly half, we need to check the ls bits */
|
||||
orl %edx,%edx
|
||||
jnz LGreater_Half_53 /* greater than half, increment needed */
|
||||
|
||||
/* Exactly half, increment only if 53rd bit is 1 (round to even) */
|
||||
testl $0x00000800,%ebx
|
||||
jz LTruncate_53
|
||||
|
||||
LGreater_Half_53: /* Rounding: increment at the 53rd bit */
|
||||
LDo_53_round_up:
|
||||
movb LOST_UP,FPU_bits_lost
|
||||
andl $0xfffff800,%ebx /* Truncate to 53 bits */
|
||||
addl $0x00000800,%ebx
|
||||
adcl $0,%eax
|
||||
jmp LCheck_Round_Overflow
|
||||
|
||||
LCheck_truncate_53:
|
||||
movl %ebx,%ecx
|
||||
andl $0x000007ff,%ecx
|
||||
orl %edx,%ecx
|
||||
jz LRe_normalise
|
||||
|
||||
LTruncate_53:
|
||||
movb LOST_DOWN,FPU_bits_lost
|
||||
andl $0xfffff800,%ebx /* Truncate to 53 bits */
|
||||
jmp LRe_normalise
|
||||
|
||||
|
||||
/* Round etc to 64 bit precision */
|
||||
LRound_To_64:
|
||||
movl %esi,%ecx
|
||||
andl CW_RC,%ecx
|
||||
cmpl RC_RND,%ecx
|
||||
je LRound_nearest_64
|
||||
|
||||
cmpl RC_CHOP,%ecx
|
||||
je LCheck_truncate_64
|
||||
|
||||
cmpl RC_UP,%ecx /* Towards +infinity */
|
||||
je LUp_64
|
||||
|
||||
cmpl RC_DOWN,%ecx /* Towards -infinity */
|
||||
je LDown_64
|
||||
|
||||
#ifdef PARANOID
|
||||
jmp L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
LUp_64:
|
||||
cmpb SIGN_POS,SIGN(%edi)
|
||||
jne LCheck_truncate_64 /* If negative then up==truncate */
|
||||
|
||||
orl %edx,%edx
|
||||
jnz LDo_64_round_up
|
||||
jmp LRe_normalise
|
||||
|
||||
LDown_64:
|
||||
cmpb SIGN_POS,SIGN(%edi)
|
||||
je LCheck_truncate_64 /* If positive then down==truncate */
|
||||
|
||||
orl %edx,%edx
|
||||
jnz LDo_64_round_up
|
||||
jmp LRe_normalise
|
||||
|
||||
LRound_nearest_64:
|
||||
cmpl $0x80000000,%edx
|
||||
jc LCheck_truncate_64
|
||||
|
||||
jne LDo_64_round_up
|
||||
|
||||
/* Now test for round-to-even */
|
||||
testb $1,%ebx
|
||||
jz LCheck_truncate_64
|
||||
|
||||
LDo_64_round_up:
|
||||
movb LOST_UP,FPU_bits_lost
|
||||
addl $1,%ebx
|
||||
adcl $0,%eax
|
||||
|
||||
LCheck_Round_Overflow:
|
||||
jnc LRe_normalise
|
||||
|
||||
/* Overflow, adjust the result (significand to 1.0) */
|
||||
rcrl $1,%eax
|
||||
rcrl $1,%ebx
|
||||
incl EXP(%edi)
|
||||
jmp LRe_normalise
|
||||
|
||||
LCheck_truncate_64:
|
||||
orl %edx,%edx
|
||||
jz LRe_normalise
|
||||
|
||||
LTruncate_64:
|
||||
movb LOST_DOWN,FPU_bits_lost
|
||||
|
||||
LRe_normalise:
|
||||
testb $0xff,FPU_denormal
|
||||
jnz xNormalise_result
|
||||
|
||||
xL_Normalised:
|
||||
cmpb LOST_UP,FPU_bits_lost
|
||||
je xL_precision_lost_up
|
||||
|
||||
cmpb LOST_DOWN,FPU_bits_lost
|
||||
je xL_precision_lost_down
|
||||
|
||||
xL_no_precision_loss:
|
||||
/* store the result */
|
||||
movb TW_Valid,TAG(%edi)
|
||||
|
||||
xL_Store_significand:
|
||||
movl %eax,SIGH(%edi)
|
||||
movl %ebx,SIGL(%edi)
|
||||
|
||||
xorl %eax,%eax /* No errors detected. */
|
||||
|
||||
cmpl EXP_OVER,EXP(%edi)
|
||||
jge L_overflow
|
||||
|
||||
fpu_reg_round_exit:
|
||||
#ifdef REENTRANT_FPU
|
||||
popl %ebx /* adjust the stack pointer */
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
fpu_Arith_exit:
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* Set the FPU status flags to represent precision loss due to
|
||||
* round-up.
|
||||
*/
|
||||
xL_precision_lost_up:
|
||||
push %eax
|
||||
call _set_precision_flag_up
|
||||
popl %eax
|
||||
jmp xL_no_precision_loss
|
||||
|
||||
/*
|
||||
* Set the FPU status flags to represent precision loss due to
|
||||
* truncation.
|
||||
*/
|
||||
xL_precision_lost_down:
|
||||
push %eax
|
||||
call _set_precision_flag_down
|
||||
popl %eax
|
||||
jmp xL_no_precision_loss
|
||||
|
||||
|
||||
/*
|
||||
* The number is a denormal (which might get rounded up to a normal)
|
||||
* Shift the number right the required number of bits, which will
|
||||
* have to be undone later...
|
||||
*/
|
||||
xMake_denorm:
|
||||
/* The action to be taken depends upon whether the underflow
|
||||
exception is masked */
|
||||
testb CW_Underflow,%cl /* Underflow mask. */
|
||||
jz xUnmasked_underflow /* Do not make a denormal. */
|
||||
|
||||
movb DENORMAL,FPU_denormal
|
||||
|
||||
pushl %ecx /* Save */
|
||||
movl EXP_UNDER+1,%ecx
|
||||
subl EXP(%edi),%ecx
|
||||
|
||||
cmpl $64,%ecx /* shrd only works for 0..31 bits */
|
||||
jnc xDenorm_shift_more_than_63
|
||||
|
||||
cmpl $32,%ecx /* shrd only works for 0..31 bits */
|
||||
jnc xDenorm_shift_more_than_32
|
||||
|
||||
/*
|
||||
* We got here without jumps by assuming that the most common requirement
|
||||
* is for a small de-normalising shift.
|
||||
* Shift by [1..31] bits
|
||||
*/
|
||||
addl %ecx,EXP(%edi)
|
||||
orl %edx,%edx /* extension */
|
||||
setne %ch /* Save whether %edx is non-zero */
|
||||
xorl %edx,%edx
|
||||
shrd %cl,%ebx,%edx
|
||||
shrd %cl,%eax,%ebx
|
||||
shr %cl,%eax
|
||||
orb %ch,%dl
|
||||
popl %ecx
|
||||
jmp xDenorm_done
|
||||
|
||||
/* Shift by [32..63] bits */
|
||||
xDenorm_shift_more_than_32:
|
||||
addl %ecx,EXP(%edi)
|
||||
subb $32,%cl
|
||||
orl %edx,%edx
|
||||
setne %ch
|
||||
orb %ch,%bl
|
||||
xorl %edx,%edx
|
||||
shrd %cl,%ebx,%edx
|
||||
shrd %cl,%eax,%ebx
|
||||
shr %cl,%eax
|
||||
orl %edx,%edx /* test these 32 bits */
|
||||
setne %cl
|
||||
orb %ch,%bl
|
||||
orb %cl,%bl
|
||||
movl %ebx,%edx
|
||||
movl %eax,%ebx
|
||||
xorl %eax,%eax
|
||||
popl %ecx
|
||||
jmp xDenorm_done
|
||||
|
||||
/* Shift by [64..) bits */
|
||||
xDenorm_shift_more_than_63:
|
||||
cmpl $64,%ecx
|
||||
jne xDenorm_shift_more_than_64
|
||||
|
||||
/* Exactly 64 bit shift */
|
||||
addl %ecx,EXP(%edi)
|
||||
xorl %ecx,%ecx
|
||||
orl %edx,%edx
|
||||
setne %cl
|
||||
orl %ebx,%ebx
|
||||
setne %ch
|
||||
orb %ch,%cl
|
||||
orb %cl,%al
|
||||
movl %eax,%edx
|
||||
xorl %eax,%eax
|
||||
xorl %ebx,%ebx
|
||||
popl %ecx
|
||||
jmp xDenorm_done
|
||||
|
||||
xDenorm_shift_more_than_64:
|
||||
movl EXP_UNDER+1,EXP(%edi)
|
||||
/* This is easy, %eax must be non-zero, so.. */
|
||||
movl $1,%edx
|
||||
xorl %eax,%eax
|
||||
xorl %ebx,%ebx
|
||||
popl %ecx
|
||||
jmp xDenorm_done
|
||||
|
||||
|
||||
xUnmasked_underflow:
|
||||
movb UNMASKED_UNDERFLOW,FPU_denormal
|
||||
jmp xDenorm_done
|
||||
|
||||
|
||||
/* Undo the de-normalisation. */
|
||||
xNormalise_result:
|
||||
cmpb UNMASKED_UNDERFLOW,FPU_denormal
|
||||
je xSignal_underflow
|
||||
|
||||
/* The number must be a denormal if we got here. */
|
||||
#ifdef PARANOID
|
||||
/* But check it... just in case. */
|
||||
cmpl EXP_UNDER+1,EXP(%edi)
|
||||
jne L_norm_bugged
|
||||
#endif PARANOID
|
||||
|
||||
#ifdef PECULIAR_486
|
||||
/*
|
||||
* This implements a special feature of 80486 behaviour.
|
||||
* Underflow will be signalled even if the number is
|
||||
* not a denormal after rounding.
|
||||
* This difference occurs only for masked underflow, and not
|
||||
* in the unmasked case.
|
||||
* Actual 80486 behaviour differs from this in some circumstances.
|
||||
*/
|
||||
orl %eax,%eax /* ms bits */
|
||||
js LNormalise_shift_done /* Will be masked underflow */
|
||||
#endif PECULIAR_486
|
||||
|
||||
orl %eax,%eax /* ms bits */
|
||||
js xL_Normalised /* No longer a denormal */
|
||||
|
||||
jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits */
|
||||
|
||||
orl %ebx,%ebx
|
||||
jz L_underflow_to_zero /* The contents are zero */
|
||||
|
||||
/* Shift left 32 - 63 bits */
|
||||
movl %ebx,%eax
|
||||
xorl %ebx,%ebx
|
||||
subl $32,EXP(%edi)
|
||||
|
||||
LNormalise_shift_up_to_31:
|
||||
bsrl %eax,%ecx /* get the required shift in %ecx */
|
||||
subl $31,%ecx
|
||||
negl %ecx
|
||||
shld %cl,%ebx,%eax
|
||||
shl %cl,%ebx
|
||||
subl %ecx,EXP(%edi)
|
||||
|
||||
LNormalise_shift_done:
|
||||
testb $0xff,FPU_bits_lost /* bits lost == underflow */
|
||||
jz xL_Normalised
|
||||
|
||||
/* There must be a masked underflow */
|
||||
push %eax
|
||||
pushl EX_Underflow
|
||||
call _exception
|
||||
popl %eax
|
||||
popl %eax
|
||||
jmp xL_Normalised
|
||||
|
||||
|
||||
/*
|
||||
* The operations resulted in a number too small to represent.
|
||||
* Masked response.
|
||||
*/
|
||||
L_underflow_to_zero:
|
||||
push %eax
|
||||
call _set_precision_flag_down
|
||||
popl %eax
|
||||
|
||||
push %eax
|
||||
pushl EX_Underflow
|
||||
call _exception
|
||||
popl %eax
|
||||
popl %eax
|
||||
|
||||
/* Reduce the exponent to EXP_UNDER */
|
||||
movl EXP_UNDER,EXP(%edi)
|
||||
movb TW_Zero,TAG(%edi)
|
||||
jmp xL_Store_significand
|
||||
|
||||
|
||||
/* The operations resulted in a number too large to represent. */
|
||||
L_overflow:
|
||||
push %edi
|
||||
call _arith_overflow
|
||||
pop %edi
|
||||
jmp fpu_reg_round_exit
|
||||
|
||||
|
||||
xSignal_underflow:
|
||||
/* The number may have been changed to a non-denormal */
|
||||
/* by the rounding operations. */
|
||||
cmpl EXP_UNDER,EXP(%edi)
|
||||
jle xDo_unmasked_underflow
|
||||
|
||||
jmp xL_Normalised
|
||||
|
||||
xDo_unmasked_underflow:
|
||||
/* Increase the exponent by the magic number */
|
||||
addl $(3*(1<<13)),EXP(%edi)
|
||||
push %eax
|
||||
pushl EX_Underflow
|
||||
call EXCEPTION
|
||||
popl %eax
|
||||
popl %eax
|
||||
jmp xL_Normalised
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
/* If we ever get here then we have problems! */
|
||||
L_bugged:
|
||||
pushl EX_INTERNAL|0x201
|
||||
call EXCEPTION
|
||||
popl %ebx
|
||||
jmp L_exception_exit
|
||||
|
||||
L_norm_bugged:
|
||||
pushl EX_INTERNAL|0x216
|
||||
call EXCEPTION
|
||||
popl %ebx
|
||||
jmp L_exception_exit
|
||||
|
||||
L_entry_bugged:
|
||||
pushl EX_INTERNAL|0x217
|
||||
call EXCEPTION
|
||||
popl %ebx
|
||||
L_exception_exit:
|
||||
mov $1,%eax
|
||||
jmp fpu_reg_round_exit
|
||||
#endif PARANOID
|
189
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_add.S
Normal file
189
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_add.S
Normal file
|
@ -0,0 +1,189 @@
|
|||
.file "reg_u_add.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| reg_u_add.S |
|
||||
| |
|
||||
| Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the |
|
||||
| result in a destination FPU_REG. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
|
||||
| int control_w) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
| Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
|
||||
| Takes two valid reg f.p. numbers (TW_Valid), which are
|
||||
| treated as unsigned numbers,
|
||||
| and returns their sum as a TW_Valid or TW_S f.p. number.
|
||||
| The returned number is normalized.
|
||||
| Basic checks are performed if PARANOID is defined.
|
||||
*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "control_w.h"
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
.globl _reg_u_add
|
||||
_reg_u_add:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi /* source 1 */
|
||||
movl PARAM2,%edi /* source 2 */
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
cmpl EXP_UNDER,EXP(%esi)
|
||||
jg xOp1_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp1_not_denorm:
|
||||
cmpl EXP_UNDER,EXP(%edi)
|
||||
jg xOp2_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp2_not_denorm:
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
movl EXP(%esi),%ecx
|
||||
subl EXP(%edi),%ecx /* exp1 - exp2 */
|
||||
jge L_arg1_larger
|
||||
|
||||
/* num1 is smaller */
|
||||
movl SIGL(%esi),%ebx
|
||||
movl SIGH(%esi),%eax
|
||||
|
||||
movl %edi,%esi
|
||||
negw %cx
|
||||
jmp L_accum_loaded
|
||||
|
||||
L_arg1_larger:
|
||||
/* num1 has larger or equal exponent */
|
||||
movl SIGL(%edi),%ebx
|
||||
movl SIGH(%edi),%eax
|
||||
|
||||
L_accum_loaded:
|
||||
movl PARAM3,%edi /* destination */
|
||||
/* movb SIGN(%esi),%dl
|
||||
movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */
|
||||
|
||||
|
||||
movl EXP(%esi),%edx
|
||||
movl %edx,EXP(%edi) /* Copy exponent to destination */
|
||||
|
||||
xorl %edx,%edx /* clear the extension */
|
||||
|
||||
#ifdef PARANOID
|
||||
testl $0x80000000,%eax
|
||||
je L_bugged
|
||||
|
||||
testl $0x80000000,SIGH(%esi)
|
||||
je L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
/* The number to be shifted is in %eax:%ebx:%edx */
|
||||
cmpw $32,%cx /* shrd only works for 0..31 bits */
|
||||
jnc L_more_than_31
|
||||
|
||||
/* less than 32 bits */
|
||||
shrd %cl,%ebx,%edx
|
||||
shrd %cl,%eax,%ebx
|
||||
shr %cl,%eax
|
||||
jmp L_shift_done
|
||||
|
||||
L_more_than_31:
|
||||
cmpw $64,%cx
|
||||
jnc L_more_than_63
|
||||
|
||||
subb $32,%cl
|
||||
jz L_exactly_32
|
||||
|
||||
shrd %cl,%eax,%edx
|
||||
shr %cl,%eax
|
||||
orl %ebx,%ebx
|
||||
jz L_more_31_no_low /* none of the lowest bits is set */
|
||||
|
||||
orl $1,%edx /* record the fact in the extension */
|
||||
|
||||
L_more_31_no_low:
|
||||
movl %eax,%ebx
|
||||
xorl %eax,%eax
|
||||
jmp L_shift_done
|
||||
|
||||
L_exactly_32:
|
||||
movl %ebx,%edx
|
||||
movl %eax,%ebx
|
||||
xorl %eax,%eax
|
||||
jmp L_shift_done
|
||||
|
||||
L_more_than_63:
|
||||
cmpw $65,%cx
|
||||
jnc L_more_than_64
|
||||
|
||||
movl %eax,%edx
|
||||
orl %ebx,%ebx
|
||||
jz L_more_63_no_low
|
||||
|
||||
orl $1,%edx
|
||||
jmp L_more_63_no_low
|
||||
|
||||
L_more_than_64:
|
||||
movl $1,%edx /* The shifted nr always at least one '1' */
|
||||
|
||||
L_more_63_no_low:
|
||||
xorl %ebx,%ebx
|
||||
xorl %eax,%eax
|
||||
|
||||
L_shift_done:
|
||||
/* Now do the addition */
|
||||
addl SIGL(%esi),%ebx
|
||||
adcl SIGH(%esi),%eax
|
||||
jnc L_round_the_result
|
||||
|
||||
/* Overflow, adjust the result */
|
||||
rcrl $1,%eax
|
||||
rcrl $1,%ebx
|
||||
rcrl $1,%edx
|
||||
jnc L_no_bit_lost
|
||||
|
||||
orl $1,%edx
|
||||
|
||||
L_no_bit_lost:
|
||||
incl EXP(%edi)
|
||||
|
||||
L_round_the_result:
|
||||
jmp fpu_reg_round /* Round the result */
|
||||
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
/* If we ever get here then we have problems! */
|
||||
L_bugged:
|
||||
pushl EX_INTERNAL|0x201
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
#endif PARANOID
|
||||
|
||||
|
||||
L_exit:
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
477
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_div.S
Normal file
477
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_div.S
Normal file
|
@ -0,0 +1,477 @@
|
|||
.file "reg_u_div.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| reg_u_div.S |
|
||||
| |
|
||||
| Core division routines |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Kernel for the division routines. |
|
||||
| |
|
||||
| void reg_u_div(FPU_REG *a, FPU_REG *a, |
|
||||
| FPU_REG *dest, unsigned int control_word) |
|
||||
| |
|
||||
| Does not compute the destination exponent, but does adjust it. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
/* #define dSIGL(x) (x) */
|
||||
/* #define dSIGH(x) 4(x) */
|
||||
|
||||
|
||||
#ifdef REENTRANT_FPU
|
||||
/*
|
||||
Local storage on the stack:
|
||||
Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
|
||||
Overflow flag: ovfl_flag
|
||||
*/
|
||||
#define FPU_accum_3 -4(%ebp)
|
||||
#define FPU_accum_2 -8(%ebp)
|
||||
#define FPU_accum_1 -12(%ebp)
|
||||
#define FPU_accum_0 -16(%ebp)
|
||||
#define FPU_result_1 -20(%ebp)
|
||||
#define FPU_result_2 -24(%ebp)
|
||||
#define FPU_ovfl_flag -28(%ebp)
|
||||
|
||||
#else
|
||||
.data
|
||||
/*
|
||||
Local storage in a static area:
|
||||
Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
|
||||
Overflow flag: ovfl_flag
|
||||
*/
|
||||
.align 2,0
|
||||
FPU_accum_3:
|
||||
.long 0
|
||||
FPU_accum_2:
|
||||
.long 0
|
||||
FPU_accum_1:
|
||||
.long 0
|
||||
FPU_accum_0:
|
||||
.long 0
|
||||
FPU_result_1:
|
||||
.long 0
|
||||
FPU_result_2:
|
||||
.long 0
|
||||
FPU_ovfl_flag:
|
||||
.byte 0
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
|
||||
.globl _reg_u_div
|
||||
|
||||
.globl _divide_kernel
|
||||
|
||||
_reg_u_div:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
#ifdef REENTRANT_FPU
|
||||
subl $28,%esp
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi /* pointer to num */
|
||||
movl PARAM2,%ebx /* pointer to denom */
|
||||
movl PARAM3,%edi /* pointer to answer */
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
movl EXP(%esi),%eax
|
||||
cmpl EXP_UNDER,%eax
|
||||
jg xOp1_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp1_not_denorm:
|
||||
movl EXP(%ebx),%eax
|
||||
cmpl EXP_UNDER,%eax
|
||||
jg xOp2_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp2_not_denorm:
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
_divide_kernel:
|
||||
#ifdef PARANOID
|
||||
/* testl $0x80000000, SIGH(%esi) // Dividend */
|
||||
/* je L_bugged */
|
||||
testl $0x80000000, SIGH(%ebx) /* Divisor */
|
||||
je L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
/* Check if the divisor can be treated as having just 32 bits */
|
||||
cmpl $0,SIGL(%ebx)
|
||||
jnz L_Full_Division /* Can't do a quick divide */
|
||||
|
||||
/* We should be able to zip through the division here */
|
||||
movl SIGH(%ebx),%ecx /* The divisor */
|
||||
movl SIGH(%esi),%edx /* Dividend */
|
||||
movl SIGL(%esi),%eax /* Dividend */
|
||||
|
||||
cmpl %ecx,%edx
|
||||
setaeb FPU_ovfl_flag /* Keep a record */
|
||||
jb L_no_adjust
|
||||
|
||||
subl %ecx,%edx /* Prevent the overflow */
|
||||
|
||||
L_no_adjust:
|
||||
/* Divide the 64 bit number by the 32 bit denominator */
|
||||
divl %ecx
|
||||
movl %eax,FPU_result_2
|
||||
|
||||
/* Work on the remainder of the first division */
|
||||
xorl %eax,%eax
|
||||
divl %ecx
|
||||
movl %eax,FPU_result_1
|
||||
|
||||
/* Work on the remainder of the 64 bit division */
|
||||
xorl %eax,%eax
|
||||
divl %ecx
|
||||
|
||||
testb $255,FPU_ovfl_flag /* was the num > denom ? */
|
||||
je L_no_overflow
|
||||
|
||||
/* Do the shifting here */
|
||||
/* increase the exponent */
|
||||
incl EXP(%edi)
|
||||
|
||||
/* shift the mantissa right one bit */
|
||||
stc /* To set the ms bit */
|
||||
rcrl FPU_result_2
|
||||
rcrl FPU_result_1
|
||||
rcrl %eax
|
||||
|
||||
L_no_overflow:
|
||||
jmp LRound_precision /* Do the rounding as required */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Divide: Return arg1/arg2 to arg3. |
|
||||
| |
|
||||
| This routine does not use the exponents of arg1 and arg2, but does |
|
||||
| adjust the exponent of arg3. |
|
||||
| |
|
||||
| The maximum returned value is (ignoring exponents) |
|
||||
| .ffffffff ffffffff |
|
||||
| ------------------ = 1.ffffffff fffffffe |
|
||||
| .80000000 00000000 |
|
||||
| and the minimum is |
|
||||
| .80000000 00000000 |
|
||||
| ------------------ = .80000000 00000001 (rounded) |
|
||||
| .ffffffff ffffffff |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
L_Full_Division:
|
||||
/* Save extended dividend in local register */
|
||||
movl SIGL(%esi),%eax
|
||||
movl %eax,FPU_accum_2
|
||||
movl SIGH(%esi),%eax
|
||||
movl %eax,FPU_accum_3
|
||||
xorl %eax,%eax
|
||||
movl %eax,FPU_accum_1 /* zero the extension */
|
||||
movl %eax,FPU_accum_0 /* zero the extension */
|
||||
|
||||
movl SIGL(%esi),%eax /* Get the current num */
|
||||
movl SIGH(%esi),%edx
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Initialization done.
|
||||
Do the first 32 bits. */
|
||||
|
||||
movb $0,FPU_ovfl_flag
|
||||
cmpl SIGH(%ebx),%edx /* Test for imminent overflow */
|
||||
jb LLess_than_1
|
||||
ja LGreater_than_1
|
||||
|
||||
cmpl SIGL(%ebx),%eax
|
||||
jb LLess_than_1
|
||||
|
||||
LGreater_than_1:
|
||||
/* The dividend is greater or equal, would cause overflow */
|
||||
setaeb FPU_ovfl_flag /* Keep a record */
|
||||
|
||||
subl SIGL(%ebx),%eax
|
||||
sbbl SIGH(%ebx),%edx /* Prevent the overflow */
|
||||
movl %eax,FPU_accum_2
|
||||
movl %edx,FPU_accum_3
|
||||
|
||||
LLess_than_1:
|
||||
/* At this point, we have a dividend < divisor, with a record of
|
||||
adjustment in FPU_ovfl_flag */
|
||||
|
||||
/* We will divide by a number which is too large */
|
||||
movl SIGH(%ebx),%ecx
|
||||
addl $1,%ecx
|
||||
jnc LFirst_div_not_1
|
||||
|
||||
/* here we need to divide by 100000000h,
|
||||
i.e., no division at all.. */
|
||||
mov %edx,%eax
|
||||
jmp LFirst_div_done
|
||||
|
||||
LFirst_div_not_1:
|
||||
divl %ecx /* Divide the numerator by the augmented
|
||||
denom ms dw */
|
||||
|
||||
LFirst_div_done:
|
||||
movl %eax,FPU_result_2 /* Put the result in the answer */
|
||||
|
||||
mull SIGH(%ebx) /* mul by the ms dw of the denom */
|
||||
|
||||
subl %eax,FPU_accum_2 /* Subtract from the num local reg */
|
||||
sbbl %edx,FPU_accum_3
|
||||
|
||||
movl FPU_result_2,%eax /* Get the result back */
|
||||
mull SIGL(%ebx) /* now mul the ls dw of the denom */
|
||||
|
||||
subl %eax,FPU_accum_1 /* Subtract from the num local reg */
|
||||
sbbl %edx,FPU_accum_2
|
||||
sbbl $0,FPU_accum_3
|
||||
je LDo_2nd_32_bits /* Must check for non-zero result here */
|
||||
|
||||
#ifdef PARANOID
|
||||
jb L_bugged_1
|
||||
#endif PARANOID
|
||||
|
||||
/* need to subtract another once of the denom */
|
||||
incl FPU_result_2 /* Correct the answer */
|
||||
|
||||
movl SIGL(%ebx),%eax
|
||||
movl SIGH(%ebx),%edx
|
||||
subl %eax,FPU_accum_1 /* Subtract from the num local reg */
|
||||
sbbl %edx,FPU_accum_2
|
||||
|
||||
#ifdef PARANOID
|
||||
sbbl $0,FPU_accum_3
|
||||
jne L_bugged_1 /* Must check for non-zero result here */
|
||||
#endif PARANOID
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Half of the main problem is done, there is just a reduced numerator
|
||||
to handle now.
|
||||
Work with the second 32 bits, FPU_accum_0 not used from now on */
|
||||
LDo_2nd_32_bits:
|
||||
movl FPU_accum_2,%edx /* get the reduced num */
|
||||
movl FPU_accum_1,%eax
|
||||
|
||||
/* need to check for possible subsequent overflow */
|
||||
cmpl SIGH(%ebx),%edx
|
||||
jb LDo_2nd_div
|
||||
ja LPrevent_2nd_overflow
|
||||
|
||||
cmpl SIGL(%ebx),%eax
|
||||
jb LDo_2nd_div
|
||||
|
||||
LPrevent_2nd_overflow:
|
||||
/* The numerator is greater or equal, would cause overflow */
|
||||
/* prevent overflow */
|
||||
subl SIGL(%ebx),%eax
|
||||
sbbl SIGH(%ebx),%edx
|
||||
movl %edx,FPU_accum_2
|
||||
movl %eax,FPU_accum_1
|
||||
|
||||
incl FPU_result_2 /* Reflect the subtraction in the answer */
|
||||
|
||||
#ifdef PARANOID
|
||||
je L_bugged_2 /* Can't bump the result to 1.0 */
|
||||
#endif PARANOID
|
||||
|
||||
LDo_2nd_div:
|
||||
cmpl $0,%ecx /* augmented denom msw */
|
||||
jnz LSecond_div_not_1
|
||||
|
||||
/* %ecx == 0, we are dividing by 1.0 */
|
||||
mov %edx,%eax
|
||||
jmp LSecond_div_done
|
||||
|
||||
LSecond_div_not_1:
|
||||
divl %ecx /* Divide the numerator by the denom ms dw */
|
||||
|
||||
LSecond_div_done:
|
||||
movl %eax,FPU_result_1 /* Put the result in the answer */
|
||||
|
||||
mull SIGH(%ebx) /* mul by the ms dw of the denom */
|
||||
|
||||
subl %eax,FPU_accum_1 /* Subtract from the num local reg */
|
||||
sbbl %edx,FPU_accum_2
|
||||
|
||||
#ifdef PARANOID
|
||||
jc L_bugged_2
|
||||
#endif PARANOID
|
||||
|
||||
movl FPU_result_1,%eax /* Get the result back */
|
||||
mull SIGL(%ebx) /* now mul the ls dw of the denom */
|
||||
|
||||
subl %eax,FPU_accum_0 /* Subtract from the num local reg */
|
||||
sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */
|
||||
sbbl $0,FPU_accum_2
|
||||
|
||||
#ifdef PARANOID
|
||||
jc L_bugged_2
|
||||
#endif PARANOID
|
||||
|
||||
jz LDo_3rd_32_bits
|
||||
|
||||
#ifdef PARANOID
|
||||
cmpl $1,FPU_accum_2
|
||||
jne L_bugged_2
|
||||
#endif PARANOID
|
||||
|
||||
/* need to subtract another once of the denom */
|
||||
movl SIGL(%ebx),%eax
|
||||
movl SIGH(%ebx),%edx
|
||||
subl %eax,FPU_accum_0 /* Subtract from the num local reg */
|
||||
sbbl %edx,FPU_accum_1
|
||||
sbbl $0,FPU_accum_2
|
||||
|
||||
#ifdef PARANOID
|
||||
jc L_bugged_2
|
||||
jne L_bugged_2
|
||||
#endif PARANOID
|
||||
|
||||
addl $1,FPU_result_1 /* Correct the answer */
|
||||
adcl $0,FPU_result_2
|
||||
|
||||
#ifdef PARANOID
|
||||
jc L_bugged_2 /* Must check for non-zero result here */
|
||||
#endif PARANOID
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* The division is essentially finished here, we just need to perform
|
||||
tidying operations.
|
||||
Deal with the 3rd 32 bits */
|
||||
LDo_3rd_32_bits:
|
||||
movl FPU_accum_1,%edx /* get the reduced num */
|
||||
movl FPU_accum_0,%eax
|
||||
|
||||
/* need to check for possible subsequent overflow */
|
||||
cmpl SIGH(%ebx),%edx /* denom */
|
||||
jb LRound_prep
|
||||
ja LPrevent_3rd_overflow
|
||||
|
||||
cmpl SIGL(%ebx),%eax /* denom */
|
||||
jb LRound_prep
|
||||
|
||||
LPrevent_3rd_overflow:
|
||||
/* prevent overflow */
|
||||
subl SIGL(%ebx),%eax
|
||||
sbbl SIGH(%ebx),%edx
|
||||
movl %edx,FPU_accum_1
|
||||
movl %eax,FPU_accum_0
|
||||
|
||||
addl $1,FPU_result_1 /* Reflect the subtraction in the answer */
|
||||
adcl $0,FPU_result_2
|
||||
jne LRound_prep
|
||||
jnc LRound_prep
|
||||
|
||||
/* This is a tricky spot, there is an overflow of the answer */
|
||||
movb $255,FPU_ovfl_flag /* Overflow -> 1.000 */
|
||||
|
||||
LRound_prep:
|
||||
/*
|
||||
* Prepare for rounding.
|
||||
* To test for rounding, we just need to compare 2*accum with the
|
||||
* denom.
|
||||
*/
|
||||
movl FPU_accum_0,%ecx
|
||||
movl FPU_accum_1,%edx
|
||||
movl %ecx,%eax
|
||||
orl %edx,%eax
|
||||
jz LRound_ovfl /* The accumulator contains zero. */
|
||||
|
||||
/* Multiply by 2 */
|
||||
clc
|
||||
rcll $1,%ecx
|
||||
rcll $1,%edx
|
||||
jc LRound_large /* No need to compare, denom smaller */
|
||||
|
||||
subl SIGL(%ebx),%ecx
|
||||
sbbl SIGH(%ebx),%edx
|
||||
jnc LRound_not_small
|
||||
|
||||
movl $0x70000000,%eax /* Denom was larger */
|
||||
jmp LRound_ovfl
|
||||
|
||||
LRound_not_small:
|
||||
jnz LRound_large
|
||||
|
||||
movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */
|
||||
jmp LRound_ovfl
|
||||
|
||||
LRound_large:
|
||||
movl $0xff000000,%eax /* Denom was smaller */
|
||||
|
||||
LRound_ovfl:
|
||||
/* We are now ready to deal with rounding, but first we must get
|
||||
the bits properly aligned */
|
||||
testb $255,FPU_ovfl_flag /* was the num > denom ? */
|
||||
je LRound_precision
|
||||
|
||||
incl EXP(%edi)
|
||||
|
||||
/* shift the mantissa right one bit */
|
||||
stc /* Will set the ms bit */
|
||||
rcrl FPU_result_2
|
||||
rcrl FPU_result_1
|
||||
rcrl %eax
|
||||
|
||||
/* Round the result as required */
|
||||
LRound_precision:
|
||||
decl EXP(%edi) /* binary point between 1st & 2nd bits */
|
||||
|
||||
movl %eax,%edx
|
||||
movl FPU_result_1,%ebx
|
||||
movl FPU_result_2,%eax
|
||||
jmp fpu_reg_round
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
/* The logic is wrong if we got here */
|
||||
L_bugged:
|
||||
pushl EX_INTERNAL|0x202
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
|
||||
L_bugged_1:
|
||||
pushl EX_INTERNAL|0x203
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
|
||||
L_bugged_2:
|
||||
pushl EX_INTERNAL|0x204
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
|
||||
L_exit:
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
|
||||
leave
|
||||
ret
|
||||
#endif PARANOID
|
163
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_mul.S
Normal file
163
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_mul.S
Normal file
|
@ -0,0 +1,163 @@
|
|||
.file "reg_u_mul.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| reg_u_mul.S |
|
||||
| |
|
||||
| Core multiplication routine |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| Basic multiplication routine. |
|
||||
| Does not check the resulting exponent for overflow/underflow |
|
||||
| |
|
||||
| reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
|
||||
| |
|
||||
| Internal working is at approx 128 bits. |
|
||||
| Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "control_w.h"
|
||||
|
||||
|
||||
|
||||
#ifdef REENTRANT_FPU
|
||||
/* Local storage on the stack: */
|
||||
#define FPU_accum_0 -4(%ebp) /* ms word */
|
||||
#define FPU_accum_1 -8(%ebp)
|
||||
|
||||
#else
|
||||
/* Local storage in a static area: */
|
||||
.data
|
||||
.align 4,0
|
||||
FPU_accum_0:
|
||||
.long 0
|
||||
FPU_accum_1:
|
||||
.long 0
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
|
||||
.globl _reg_u_mul
|
||||
_reg_u_mul:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
#ifdef REENTRANT_FPU
|
||||
subl $8,%esp
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi
|
||||
movl PARAM2,%edi
|
||||
|
||||
#ifdef PARANOID
|
||||
testl $0x80000000,SIGH(%esi)
|
||||
jz L_bugged
|
||||
testl $0x80000000,SIGH(%edi)
|
||||
jz L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
movl EXP(%esi),%eax
|
||||
cmpl EXP_UNDER,%eax
|
||||
jg xOp1_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp1_not_denorm:
|
||||
movl EXP(%edi),%eax
|
||||
cmpl EXP_UNDER,%eax
|
||||
jg xOp2_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp2_not_denorm:
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
xorl %ecx,%ecx
|
||||
xorl %ebx,%ebx
|
||||
|
||||
movl SIGL(%esi),%eax
|
||||
mull SIGL(%edi)
|
||||
movl %eax,FPU_accum_0
|
||||
movl %edx,FPU_accum_1
|
||||
|
||||
movl SIGL(%esi),%eax
|
||||
mull SIGH(%edi)
|
||||
addl %eax,FPU_accum_1
|
||||
adcl %edx,%ebx
|
||||
/* adcl $0,%ecx // overflow here is not possible */
|
||||
|
||||
movl SIGH(%esi),%eax
|
||||
mull SIGL(%edi)
|
||||
addl %eax,FPU_accum_1
|
||||
adcl %edx,%ebx
|
||||
adcl $0,%ecx
|
||||
|
||||
movl SIGH(%esi),%eax
|
||||
mull SIGH(%edi)
|
||||
addl %eax,%ebx
|
||||
adcl %edx,%ecx
|
||||
|
||||
movl EXP(%esi),%eax /* Compute the exponent */
|
||||
addl EXP(%edi),%eax
|
||||
subl EXP_BIAS-1,%eax
|
||||
|
||||
/* Have now finished with the sources */
|
||||
movl PARAM3,%edi /* Point to the destination */
|
||||
movl %eax,EXP(%edi)
|
||||
|
||||
/* Now make sure that the result is normalized */
|
||||
testl $0x80000000,%ecx
|
||||
jnz LResult_Normalised
|
||||
|
||||
/* Normalize by shifting left one bit */
|
||||
shll $1,FPU_accum_0
|
||||
rcll $1,FPU_accum_1
|
||||
rcll $1,%ebx
|
||||
rcll $1,%ecx
|
||||
decl EXP(%edi)
|
||||
|
||||
LResult_Normalised:
|
||||
movl FPU_accum_0,%eax
|
||||
movl FPU_accum_1,%edx
|
||||
orl %eax,%eax
|
||||
jz L_extent_zero
|
||||
|
||||
orl $1,%edx
|
||||
|
||||
L_extent_zero:
|
||||
movl %ecx,%eax
|
||||
jmp fpu_reg_round
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
L_bugged:
|
||||
pushl EX_INTERNAL|0x205
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_exit
|
||||
|
||||
L_exit:
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
#endif PARANOID
|
||||
|
292
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_sub.S
Normal file
292
source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_sub.S
Normal file
|
@ -0,0 +1,292 @@
|
|||
.file "reg_u_sub.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| reg_u_sub.S |
|
||||
| |
|
||||
| Core floating point subtraction routine. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
|
||||
| int control_w) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
| Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
|
||||
| Takes two valid reg f.p. numbers (TW_Valid), which are
|
||||
| treated as unsigned numbers,
|
||||
| and returns their difference as a TW_Valid or TW_Zero f.p.
|
||||
| number.
|
||||
| The first number (arg1) must be the larger.
|
||||
| The returned number is normalized.
|
||||
| Basic checks are performed if PARANOID is defined.
|
||||
*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "control_w.h"
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
.globl _reg_u_sub
|
||||
_reg_u_sub:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi /* source 1 */
|
||||
movl PARAM2,%edi /* source 2 */
|
||||
|
||||
#ifdef DENORM_OPERAND
|
||||
cmpl EXP_UNDER,EXP(%esi)
|
||||
jg xOp1_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp1_not_denorm:
|
||||
cmpl EXP_UNDER,EXP(%edi)
|
||||
jg xOp2_not_denorm
|
||||
|
||||
call _denormal_operand
|
||||
orl %eax,%eax
|
||||
jnz fpu_Arith_exit
|
||||
|
||||
xOp2_not_denorm:
|
||||
#endif DENORM_OPERAND
|
||||
|
||||
movl EXP(%esi),%ecx
|
||||
subl EXP(%edi),%ecx /* exp1 - exp2 */
|
||||
|
||||
#ifdef PARANOID
|
||||
/* source 2 is always smaller than source 1 */
|
||||
js L_bugged_1
|
||||
|
||||
testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
|
||||
je L_bugged_2
|
||||
|
||||
testl $0x80000000,SIGH(%esi)
|
||||
je L_bugged_2
|
||||
#endif PARANOID
|
||||
|
||||
/*--------------------------------------+
|
||||
| Form a register holding the |
|
||||
| smaller number |
|
||||
+--------------------------------------*/
|
||||
movl SIGH(%edi),%eax /* register ms word */
|
||||
movl SIGL(%edi),%ebx /* register ls word */
|
||||
|
||||
movl PARAM3,%edi /* destination */
|
||||
movl EXP(%esi),%edx
|
||||
movl %edx,EXP(%edi) /* Copy exponent to destination */
|
||||
/* movb SIGN(%esi),%dl
|
||||
movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */
|
||||
|
||||
xorl %edx,%edx /* register extension */
|
||||
|
||||
/*--------------------------------------+
|
||||
| Shift the temporary register |
|
||||
| right the required number of |
|
||||
| places. |
|
||||
+--------------------------------------*/
|
||||
L_shift_r:
|
||||
cmpl $32,%ecx /* shrd only works for 0..31 bits */
|
||||
jnc L_more_than_31
|
||||
|
||||
/* less than 32 bits */
|
||||
shrd %cl,%ebx,%edx
|
||||
shrd %cl,%eax,%ebx
|
||||
shr %cl,%eax
|
||||
jmp L_shift_done
|
||||
|
||||
L_more_than_31:
|
||||
cmpl $64,%ecx
|
||||
jnc L_more_than_63
|
||||
|
||||
subb $32,%cl
|
||||
jz L_exactly_32
|
||||
|
||||
shrd %cl,%eax,%edx
|
||||
shr %cl,%eax
|
||||
orl %ebx,%ebx
|
||||
jz L_more_31_no_low /* none of the lowest bits is set */
|
||||
|
||||
orl $1,%edx /* record the fact in the extension */
|
||||
|
||||
L_more_31_no_low:
|
||||
movl %eax,%ebx
|
||||
xorl %eax,%eax
|
||||
jmp L_shift_done
|
||||
|
||||
L_exactly_32:
|
||||
movl %ebx,%edx
|
||||
movl %eax,%ebx
|
||||
xorl %eax,%eax
|
||||
jmp L_shift_done
|
||||
|
||||
L_more_than_63:
|
||||
cmpw $65,%cx
|
||||
jnc L_more_than_64
|
||||
|
||||
/* Shift right by 64 bits */
|
||||
movl %eax,%edx
|
||||
orl %ebx,%ebx
|
||||
jz L_more_63_no_low
|
||||
|
||||
orl $1,%edx
|
||||
jmp L_more_63_no_low
|
||||
|
||||
L_more_than_64:
|
||||
jne L_more_than_65
|
||||
|
||||
/* Shift right by 65 bits */
|
||||
/* Carry is clear if we get here */
|
||||
movl %eax,%edx
|
||||
rcrl %edx
|
||||
jnc L_shift_65_nc
|
||||
|
||||
orl $1,%edx
|
||||
jmp L_more_63_no_low
|
||||
|
||||
L_shift_65_nc:
|
||||
orl %ebx,%ebx
|
||||
jz L_more_63_no_low
|
||||
|
||||
orl $1,%edx
|
||||
jmp L_more_63_no_low
|
||||
|
||||
L_more_than_65:
|
||||
movl $1,%edx /* The shifted nr always at least one '1' */
|
||||
|
||||
L_more_63_no_low:
|
||||
xorl %ebx,%ebx
|
||||
xorl %eax,%eax
|
||||
|
||||
L_shift_done:
|
||||
L_subtr:
|
||||
/*------------------------------+
|
||||
| Do the subtraction |
|
||||
+------------------------------*/
|
||||
xorl %ecx,%ecx
|
||||
subl %edx,%ecx
|
||||
movl %ecx,%edx
|
||||
movl SIGL(%esi),%ecx
|
||||
sbbl %ebx,%ecx
|
||||
movl %ecx,%ebx
|
||||
movl SIGH(%esi),%ecx
|
||||
sbbl %eax,%ecx
|
||||
movl %ecx,%eax
|
||||
|
||||
#ifdef PARANOID
|
||||
/* We can never get a borrow */
|
||||
jc L_bugged
|
||||
#endif PARANOID
|
||||
|
||||
/*--------------------------------------+
|
||||
| Normalize the result |
|
||||
+--------------------------------------*/
|
||||
testl $0x80000000,%eax
|
||||
jnz L_round /* no shifting needed */
|
||||
|
||||
orl %eax,%eax
|
||||
jnz L_shift_1 /* shift left 1 - 31 bits */
|
||||
|
||||
orl %ebx,%ebx
|
||||
jnz L_shift_32 /* shift left 32 - 63 bits */
|
||||
|
||||
/*
|
||||
* A rare case, the only one which is non-zero if we got here
|
||||
* is: 1000000 .... 0000
|
||||
* -0111111 .... 1111 1
|
||||
* --------------------
|
||||
* 0000000 .... 0000 1
|
||||
*/
|
||||
|
||||
cmpl $0x80000000,%edx
|
||||
jnz L_must_be_zero
|
||||
|
||||
/* Shift left 64 bits */
|
||||
subl $64,EXP(%edi)
|
||||
xchg %edx,%eax
|
||||
jmp fpu_reg_round
|
||||
|
||||
L_must_be_zero:
|
||||
#ifdef PARANOID
|
||||
orl %edx,%edx
|
||||
jnz L_bugged_3
|
||||
#endif PARANOID
|
||||
|
||||
/* The result is zero */
|
||||
movb TW_Zero,TAG(%edi)
|
||||
movl $0,EXP(%edi) /* exponent */
|
||||
movl $0,SIGL(%edi)
|
||||
movl $0,SIGH(%edi)
|
||||
jmp L_exit /* %eax contains zero */
|
||||
|
||||
L_shift_32:
|
||||
movl %ebx,%eax
|
||||
movl %edx,%ebx
|
||||
movl $0,%edx
|
||||
subl $32,EXP(%edi) /* Can get underflow here */
|
||||
|
||||
/* We need to shift left by 1 - 31 bits */
|
||||
L_shift_1:
|
||||
bsrl %eax,%ecx /* get the required shift in %ecx */
|
||||
subl $31,%ecx
|
||||
negl %ecx
|
||||
shld %cl,%ebx,%eax
|
||||
shld %cl,%edx,%ebx
|
||||
shl %cl,%edx
|
||||
subl %ecx,EXP(%edi) /* Can get underflow here */
|
||||
|
||||
L_round:
|
||||
jmp fpu_reg_round /* Round the result */
|
||||
|
||||
|
||||
#ifdef PARANOID
|
||||
L_bugged_1:
|
||||
pushl EX_INTERNAL|0x206
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_error_exit
|
||||
|
||||
L_bugged_2:
|
||||
pushl EX_INTERNAL|0x209
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_error_exit
|
||||
|
||||
L_bugged_3:
|
||||
pushl EX_INTERNAL|0x210
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_error_exit
|
||||
|
||||
L_bugged_4:
|
||||
pushl EX_INTERNAL|0x211
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_error_exit
|
||||
|
||||
L_bugged:
|
||||
pushl EX_INTERNAL|0x212
|
||||
call EXCEPTION
|
||||
pop %ebx
|
||||
jmp L_error_exit
|
||||
#endif PARANOID
|
||||
|
||||
|
||||
L_error_exit:
|
||||
movl $1,%eax
|
||||
L_exit:
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
65
source/THIRDPARTY/linux-old/drivers/FPU-emu/status_w.h
Normal file
65
source/THIRDPARTY/linux-old/drivers/FPU-emu/status_w.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| status_w.h |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _STATUS_H_
|
||||
#define _STATUS_H_
|
||||
|
||||
#include "fpu_emu.h" /* for definition of PECULIAR_486 */
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#define Const__(x) $##x
|
||||
#else
|
||||
#define Const__(x) x
|
||||
#endif
|
||||
|
||||
#define SW_Backward Const__(0x8000) /* backward compatibility */
|
||||
#define SW_C3 Const__(0x4000) /* condition bit 3 */
|
||||
#define SW_Top Const__(0x3800) /* top of stack */
|
||||
#define SW_Top_Shift Const__(11) /* shift for top of stack bits */
|
||||
#define SW_C2 Const__(0x0400) /* condition bit 2 */
|
||||
#define SW_C1 Const__(0x0200) /* condition bit 1 */
|
||||
#define SW_C0 Const__(0x0100) /* condition bit 0 */
|
||||
#define SW_Summary Const__(0x0080) /* exception summary */
|
||||
#define SW_Stack_Fault Const__(0x0040) /* stack fault */
|
||||
#define SW_Precision Const__(0x0020) /* loss of precision */
|
||||
#define SW_Underflow Const__(0x0010) /* underflow */
|
||||
#define SW_Overflow Const__(0x0008) /* overflow */
|
||||
#define SW_Zero_Div Const__(0x0004) /* divide by zero */
|
||||
#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
|
||||
#define SW_Invalid Const__(0x0001) /* invalid operation */
|
||||
|
||||
#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#define COMP_A_gt_B 1
|
||||
#define COMP_A_eq_B 2
|
||||
#define COMP_A_lt_B 3
|
||||
#define COMP_No_Comp 4
|
||||
#define COMP_Denormal 0x20
|
||||
#define COMP_NaN 0x40
|
||||
#define COMP_SNaN 0x80
|
||||
|
||||
#define status_word() \
|
||||
((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
|
||||
#define setcc(cc) ({ \
|
||||
partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \
|
||||
partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); })
|
||||
|
||||
#ifdef PECULIAR_486
|
||||
/* Default, this conveys no information, but an 80486 does it. */
|
||||
/* Clear the SW_C1 bit, "other bits undefined". */
|
||||
# define clear_C1() { partial_status &= ~SW_C1; }
|
||||
# else
|
||||
# define clear_C1()
|
||||
#endif PECULIAR_486
|
||||
|
||||
#endif __ASSEMBLER__
|
||||
|
||||
#endif _STATUS_H_
|
13
source/THIRDPARTY/linux-old/drivers/FPU-emu/version.h
Normal file
13
source/THIRDPARTY/linux-old/drivers/FPU-emu/version.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*---------------------------------------------------------------------------+
|
||||
| version.h |
|
||||
| |
|
||||
| |
|
||||
| Copyright (C) 1992,1993,1994 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#define FPU_VERSION "wm-FPU-emu version Beta 1.9"
|
||||
|
208
source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_shrx.S
Normal file
208
source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_shrx.S
Normal file
|
@ -0,0 +1,208 @@
|
|||
.file "wm_shrx.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| wm_shrx.S |
|
||||
| |
|
||||
| 64 bit right shift functions |
|
||||
| |
|
||||
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| unsigned shrx(void *arg1, unsigned arg2) |
|
||||
| and |
|
||||
| unsigned shrxs(void *arg1, unsigned arg2) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fpu_asm.h"
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| unsigned shrx(void *arg1, unsigned arg2) |
|
||||
| |
|
||||
| Extended shift right function. |
|
||||
| Fastest for small shifts. |
|
||||
| Shifts the 64 bit quantity pointed to by the first arg (arg1) |
|
||||
| right by the number of bits specified by the second arg (arg2). |
|
||||
| Forms a 96 bit quantity from the 64 bit arg and eax: |
|
||||
| [ 64 bit arg ][ eax ] |
|
||||
| shift right ---------> |
|
||||
| The eax register is initialized to 0 before the shifting. |
|
||||
| Results returned in the 64 bit arg and eax. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
.globl _shrx
|
||||
|
||||
_shrx:
|
||||
push %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %esi
|
||||
movl PARAM2,%ecx
|
||||
movl PARAM1,%esi
|
||||
cmpl $32,%ecx /* shrd only works for 0..31 bits */
|
||||
jnc L_more_than_31
|
||||
|
||||
/* less than 32 bits */
|
||||
pushl %ebx
|
||||
movl (%esi),%ebx /* lsl */
|
||||
movl 4(%esi),%edx /* msl */
|
||||
xorl %eax,%eax /* extension */
|
||||
shrd %cl,%ebx,%eax
|
||||
shrd %cl,%edx,%ebx
|
||||
shr %cl,%edx
|
||||
movl %ebx,(%esi)
|
||||
movl %edx,4(%esi)
|
||||
popl %ebx
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
L_more_than_31:
|
||||
cmpl $64,%ecx
|
||||
jnc L_more_than_63
|
||||
|
||||
subb $32,%cl
|
||||
movl (%esi),%eax /* lsl */
|
||||
movl 4(%esi),%edx /* msl */
|
||||
shrd %cl,%edx,%eax
|
||||
shr %cl,%edx
|
||||
movl %edx,(%esi)
|
||||
movl $0,4(%esi)
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
L_more_than_63:
|
||||
cmpl $96,%ecx
|
||||
jnc L_more_than_95
|
||||
|
||||
subb $64,%cl
|
||||
movl 4(%esi),%eax /* msl */
|
||||
shr %cl,%eax
|
||||
xorl %edx,%edx
|
||||
movl %edx,(%esi)
|
||||
movl %edx,4(%esi)
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
L_more_than_95:
|
||||
xorl %eax,%eax
|
||||
movl %eax,(%esi)
|
||||
movl %eax,4(%esi)
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| unsigned shrxs(void *arg1, unsigned arg2) |
|
||||
| |
|
||||
| Extended shift right function (optimized for small floating point |
|
||||
| integers). |
|
||||
| Shifts the 64 bit quantity pointed to by the first arg (arg1) |
|
||||
| right by the number of bits specified by the second arg (arg2). |
|
||||
| Forms a 96 bit quantity from the 64 bit arg and eax: |
|
||||
| [ 64 bit arg ][ eax ] |
|
||||
| shift right ---------> |
|
||||
| The eax register is initialized to 0 before the shifting. |
|
||||
| The lower 8 bits of eax are lost and replaced by a flag which is |
|
||||
| set (to 0x01) if any bit, apart from the first one, is set in the |
|
||||
| part which has been shifted out of the arg. |
|
||||
| Results returned in the 64 bit arg and eax. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
.globl _shrxs
|
||||
_shrxs:
|
||||
push %ebp
|
||||
movl %esp,%ebp
|
||||
pushl %esi
|
||||
pushl %ebx
|
||||
movl PARAM2,%ecx
|
||||
movl PARAM1,%esi
|
||||
cmpl $64,%ecx /* shrd only works for 0..31 bits */
|
||||
jnc Ls_more_than_63
|
||||
|
||||
cmpl $32,%ecx /* shrd only works for 0..31 bits */
|
||||
jc Ls_less_than_32
|
||||
|
||||
/* We got here without jumps by assuming that the most common requirement
|
||||
is for small integers */
|
||||
/* Shift by [32..63] bits */
|
||||
subb $32,%cl
|
||||
movl (%esi),%eax /* lsl */
|
||||
movl 4(%esi),%edx /* msl */
|
||||
xorl %ebx,%ebx
|
||||
shrd %cl,%eax,%ebx
|
||||
shrd %cl,%edx,%eax
|
||||
shr %cl,%edx
|
||||
orl %ebx,%ebx /* test these 32 bits */
|
||||
setne %bl
|
||||
test $0x7fffffff,%eax /* and 31 bits here */
|
||||
setne %bh
|
||||
orw %bx,%bx /* Any of the 63 bit set ? */
|
||||
setne %al
|
||||
movl %edx,(%esi)
|
||||
movl $0,4(%esi)
|
||||
popl %ebx
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
/* Shift by [0..31] bits */
|
||||
Ls_less_than_32:
|
||||
movl (%esi),%ebx /* lsl */
|
||||
movl 4(%esi),%edx /* msl */
|
||||
xorl %eax,%eax /* extension */
|
||||
shrd %cl,%ebx,%eax
|
||||
shrd %cl,%edx,%ebx
|
||||
shr %cl,%edx
|
||||
test $0x7fffffff,%eax /* only need to look at eax here */
|
||||
setne %al
|
||||
movl %ebx,(%esi)
|
||||
movl %edx,4(%esi)
|
||||
popl %ebx
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
/* Shift by [64..95] bits */
|
||||
Ls_more_than_63:
|
||||
cmpl $96,%ecx
|
||||
jnc Ls_more_than_95
|
||||
|
||||
subb $64,%cl
|
||||
movl (%esi),%ebx /* lsl */
|
||||
movl 4(%esi),%eax /* msl */
|
||||
xorl %edx,%edx /* extension */
|
||||
shrd %cl,%ebx,%edx
|
||||
shrd %cl,%eax,%ebx
|
||||
shr %cl,%eax
|
||||
orl %ebx,%edx
|
||||
setne %bl
|
||||
test $0x7fffffff,%eax /* only need to look at eax here */
|
||||
setne %bh
|
||||
orw %bx,%bx
|
||||
setne %al
|
||||
xorl %edx,%edx
|
||||
movl %edx,(%esi) /* set to zero */
|
||||
movl %edx,4(%esi) /* set to zero */
|
||||
popl %ebx
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
||||
|
||||
Ls_more_than_95:
|
||||
/* Shift by [96..inf) bits */
|
||||
xorl %eax,%eax
|
||||
movl (%esi),%ebx
|
||||
orl 4(%esi),%ebx
|
||||
setne %al
|
||||
xorl %ebx,%ebx
|
||||
movl %ebx,(%esi)
|
||||
movl %ebx,4(%esi)
|
||||
popl %ebx
|
||||
popl %esi
|
||||
leave
|
||||
ret
|
474
source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_sqrt.S
Normal file
474
source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_sqrt.S
Normal file
|
@ -0,0 +1,474 @@
|
|||
.file "wm_sqrt.S"
|
||||
/*---------------------------------------------------------------------------+
|
||||
| wm_sqrt.S |
|
||||
| |
|
||||
| Fixed point arithmetic square root evaluation. |
|
||||
| |
|
||||
| Copyright (C) 1992,1993 |
|
||||
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
|
||||
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
|
||||
| |
|
||||
| Call from C as: |
|
||||
| void wm_sqrt(FPU_REG *n, unsigned int control_word) |
|
||||
| |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| wm_sqrt(FPU_REG *n, unsigned int control_word) |
|
||||
| returns the square root of n in n. |
|
||||
| |
|
||||
| Use Newton's method to compute the square root of a number, which must |
|
||||
| be in the range [1.0 .. 4.0), to 64 bits accuracy. |
|
||||
| Does not check the sign or tag of the argument. |
|
||||
| Sets the exponent, but not the sign or tag of the result. |
|
||||
| |
|
||||
| The guess is kept in %esi:%edi |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
|
||||
|
||||
#ifdef REENTRANT_FPU
|
||||
/* Local storage on the stack: */
|
||||
#define FPU_accum_3 -4(%ebp) /* ms word */
|
||||
#define FPU_accum_2 -8(%ebp)
|
||||
#define FPU_accum_1 -12(%ebp)
|
||||
#define FPU_accum_0 -16(%ebp)
|
||||
|
||||
/*
|
||||
* The de-normalised argument:
|
||||
* sq_2 sq_1 sq_0
|
||||
* b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
|
||||
* ^ binary point here
|
||||
*/
|
||||
#define FPU_fsqrt_arg_2 -20(%ebp) /* ms word */
|
||||
#define FPU_fsqrt_arg_1 -24(%ebp)
|
||||
#define FPU_fsqrt_arg_0 -28(%ebp) /* ls word, at most the ms bit is set */
|
||||
|
||||
#else
|
||||
/* Local storage in a static area: */
|
||||
.data
|
||||
.align 4,0
|
||||
FPU_accum_3:
|
||||
.long 0 /* ms word */
|
||||
FPU_accum_2:
|
||||
.long 0
|
||||
FPU_accum_1:
|
||||
.long 0
|
||||
FPU_accum_0:
|
||||
.long 0
|
||||
|
||||
/* The de-normalised argument:
|
||||
sq_2 sq_1 sq_0
|
||||
b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
|
||||
^ binary point here
|
||||
*/
|
||||
FPU_fsqrt_arg_2:
|
||||
.long 0 /* ms word */
|
||||
FPU_fsqrt_arg_1:
|
||||
.long 0
|
||||
FPU_fsqrt_arg_0:
|
||||
.long 0 /* ls word, at most the ms bit is set */
|
||||
#endif REENTRANT_FPU
|
||||
|
||||
|
||||
.text
|
||||
.align 2,144
|
||||
|
||||
.globl _wm_sqrt
|
||||
_wm_sqrt:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
#ifdef REENTRANT_FPU
|
||||
subl $28,%esp
|
||||
#endif REENTRANT_FPU
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
movl PARAM1,%esi
|
||||
|
||||
movl SIGH(%esi),%eax
|
||||
movl SIGL(%esi),%ecx
|
||||
xorl %edx,%edx
|
||||
|
||||
/* We use a rough linear estimate for the first guess.. */
|
||||
|
||||
cmpl EXP_BIAS,EXP(%esi)
|
||||
jnz sqrt_arg_ge_2
|
||||
|
||||
shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */
|
||||
rcrl $1,%ecx
|
||||
rcrl $1,%edx
|
||||
|
||||
sqrt_arg_ge_2:
|
||||
/* From here on, n is never accessed directly again until it is
|
||||
replaced by the answer. */
|
||||
|
||||
movl %eax,FPU_fsqrt_arg_2 /* ms word of n */
|
||||
movl %ecx,FPU_fsqrt_arg_1
|
||||
movl %edx,FPU_fsqrt_arg_0
|
||||
|
||||
/* Make a linear first estimate */
|
||||
shrl $1,%eax
|
||||
addl $0x40000000,%eax
|
||||
movl $0xaaaaaaaa,%ecx
|
||||
mull %ecx
|
||||
shll %edx /* max result was 7fff... */
|
||||
testl $0x80000000,%edx /* but min was 3fff... */
|
||||
jnz sqrt_prelim_no_adjust
|
||||
|
||||
movl $0x80000000,%edx /* round up */
|
||||
|
||||
sqrt_prelim_no_adjust:
|
||||
movl %edx,%esi /* Our first guess */
|
||||
|
||||
/* We have now computed (approx) (2 + x) / 3, which forms the basis
|
||||
for a few iterations of Newton's method */
|
||||
|
||||
movl FPU_fsqrt_arg_2,%ecx /* ms word */
|
||||
|
||||
/*
|
||||
* From our initial estimate, three iterations are enough to get us
|
||||
* to 30 bits or so. This will then allow two iterations at better
|
||||
* precision to complete the process.
|
||||
*/
|
||||
|
||||
/* Compute (g + n/g)/2 at each iteration (g is the guess). */
|
||||
shrl %ecx /* Doing this first will prevent a divide */
|
||||
/* overflow later. */
|
||||
|
||||
movl %ecx,%edx /* msw of the arg / 2 */
|
||||
divl %esi /* current estimate */
|
||||
shrl %esi /* divide by 2 */
|
||||
addl %eax,%esi /* the new estimate */
|
||||
|
||||
movl %ecx,%edx
|
||||
divl %esi
|
||||
shrl %esi
|
||||
addl %eax,%esi
|
||||
|
||||
movl %ecx,%edx
|
||||
divl %esi
|
||||
shrl %esi
|
||||
addl %eax,%esi
|
||||
|
||||
/*
|
||||
* Now that an estimate accurate to about 30 bits has been obtained (in %esi),
|
||||
* we improve it to 60 bits or so.
|
||||
*
|
||||
* The strategy from now on is to compute new estimates from
|
||||
* guess := guess + (n - guess^2) / (2 * guess)
|
||||
*/
|
||||
|
||||
/* First, find the square of the guess */
|
||||
movl %esi,%eax
|
||||
mull %esi
|
||||
/* guess^2 now in %edx:%eax */
|
||||
|
||||
movl FPU_fsqrt_arg_1,%ecx
|
||||
subl %ecx,%eax
|
||||
movl FPU_fsqrt_arg_2,%ecx /* ms word of normalized n */
|
||||
sbbl %ecx,%edx
|
||||
jnc sqrt_stage_2_positive
|
||||
|
||||
/* Subtraction gives a negative result,
|
||||
negate the result before division. */
|
||||
notl %edx
|
||||
notl %eax
|
||||
addl $1,%eax
|
||||
adcl $0,%edx
|
||||
|
||||
divl %esi
|
||||
movl %eax,%ecx
|
||||
|
||||
movl %edx,%eax
|
||||
divl %esi
|
||||
jmp sqrt_stage_2_finish
|
||||
|
||||
sqrt_stage_2_positive:
|
||||
divl %esi
|
||||
movl %eax,%ecx
|
||||
|
||||
movl %edx,%eax
|
||||
divl %esi
|
||||
|
||||
notl %ecx
|
||||
notl %eax
|
||||
addl $1,%eax
|
||||
adcl $0,%ecx
|
||||
|
||||
sqrt_stage_2_finish:
|
||||
sarl $1,%ecx /* divide by 2 */
|
||||
rcrl $1,%eax
|
||||
|
||||
/* Form the new estimate in %esi:%edi */
|
||||
movl %eax,%edi
|
||||
addl %ecx,%esi
|
||||
|
||||
jnz sqrt_stage_2_done /* result should be [1..2) */
|
||||
|
||||
#ifdef PARANOID
|
||||
/* It should be possible to get here only if the arg is ffff....ffff */
|
||||
cmp $0xffffffff,FPU_fsqrt_arg_1
|
||||
jnz sqrt_stage_2_error
|
||||
#endif PARANOID
|
||||
|
||||
/* The best rounded result. */
|
||||
xorl %eax,%eax
|
||||
decl %eax
|
||||
movl %eax,%edi
|
||||
movl %eax,%esi
|
||||
movl $0x7fffffff,%eax
|
||||
jmp sqrt_round_result
|
||||
|
||||
#ifdef PARANOID
|
||||
sqrt_stage_2_error:
|
||||
pushl EX_INTERNAL|0x213
|
||||
call EXCEPTION
|
||||
#endif PARANOID
|
||||
|
||||
sqrt_stage_2_done:
|
||||
|
||||
/* Now the square root has been computed to better than 60 bits. */
|
||||
|
||||
/* Find the square of the guess. */
|
||||
movl %edi,%eax /* ls word of guess */
|
||||
mull %edi
|
||||
movl %edx,FPU_accum_1
|
||||
|
||||
movl %esi,%eax
|
||||
mull %esi
|
||||
movl %edx,FPU_accum_3
|
||||
movl %eax,FPU_accum_2
|
||||
|
||||
movl %edi,%eax
|
||||
mull %esi
|
||||
addl %eax,FPU_accum_1
|
||||
adcl %edx,FPU_accum_2
|
||||
adcl $0,FPU_accum_3
|
||||
|
||||
/* movl %esi,%eax */
|
||||
/* mull %edi */
|
||||
addl %eax,FPU_accum_1
|
||||
adcl %edx,FPU_accum_2
|
||||
adcl $0,FPU_accum_3
|
||||
|
||||
/* guess^2 now in FPU_accum_3:FPU_accum_2:FPU_accum_1 */
|
||||
|
||||
movl FPU_fsqrt_arg_0,%eax /* get normalized n */
|
||||
subl %eax,FPU_accum_1
|
||||
movl FPU_fsqrt_arg_1,%eax
|
||||
sbbl %eax,FPU_accum_2
|
||||
movl FPU_fsqrt_arg_2,%eax /* ms word of normalized n */
|
||||
sbbl %eax,FPU_accum_3
|
||||
jnc sqrt_stage_3_positive
|
||||
|
||||
/* Subtraction gives a negative result,
|
||||
negate the result before division */
|
||||
notl FPU_accum_1
|
||||
notl FPU_accum_2
|
||||
notl FPU_accum_3
|
||||
addl $1,FPU_accum_1
|
||||
adcl $0,FPU_accum_2
|
||||
|
||||
#ifdef PARANOID
|
||||
adcl $0,FPU_accum_3 /* This must be zero */
|
||||
jz sqrt_stage_3_no_error
|
||||
|
||||
sqrt_stage_3_error:
|
||||
pushl EX_INTERNAL|0x207
|
||||
call EXCEPTION
|
||||
|
||||
sqrt_stage_3_no_error:
|
||||
#endif PARANOID
|
||||
|
||||
movl FPU_accum_2,%edx
|
||||
movl FPU_accum_1,%eax
|
||||
divl %esi
|
||||
movl %eax,%ecx
|
||||
|
||||
movl %edx,%eax
|
||||
divl %esi
|
||||
|
||||
sarl $1,%ecx /* divide by 2 */
|
||||
rcrl $1,%eax
|
||||
|
||||
/* prepare to round the result */
|
||||
|
||||
addl %ecx,%edi
|
||||
adcl $0,%esi
|
||||
|
||||
jmp sqrt_stage_3_finished
|
||||
|
||||
sqrt_stage_3_positive:
|
||||
movl FPU_accum_2,%edx
|
||||
movl FPU_accum_1,%eax
|
||||
divl %esi
|
||||
movl %eax,%ecx
|
||||
|
||||
movl %edx,%eax
|
||||
divl %esi
|
||||
|
||||
sarl $1,%ecx /* divide by 2 */
|
||||
rcrl $1,%eax
|
||||
|
||||
/* prepare to round the result */
|
||||
|
||||
notl %eax /* Negate the correction term */
|
||||
notl %ecx
|
||||
addl $1,%eax
|
||||
adcl $0,%ecx /* carry here ==> correction == 0 */
|
||||
adcl $0xffffffff,%esi
|
||||
|
||||
addl %ecx,%edi
|
||||
adcl $0,%esi
|
||||
|
||||
sqrt_stage_3_finished:
|
||||
|
||||
/*
|
||||
* The result in %esi:%edi:%esi should be good to about 90 bits here,
|
||||
* and the rounding information here does not have sufficient accuracy
|
||||
* in a few rare cases.
|
||||
*/
|
||||
cmpl $0xffffffe0,%eax
|
||||
ja sqrt_near_exact_x
|
||||
|
||||
cmpl $0x00000020,%eax
|
||||
jb sqrt_near_exact
|
||||
|
||||
cmpl $0x7fffffe0,%eax
|
||||
jb sqrt_round_result
|
||||
|
||||
cmpl $0x80000020,%eax
|
||||
jb sqrt_get_more_precision
|
||||
|
||||
sqrt_round_result:
|
||||
/* Set up for rounding operations */
|
||||
movl %eax,%edx
|
||||
movl %esi,%eax
|
||||
movl %edi,%ebx
|
||||
movl PARAM1,%edi
|
||||
movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */
|
||||
movl PARAM2,%ecx
|
||||
jmp fpu_reg_round_sqrt
|
||||
|
||||
|
||||
sqrt_near_exact_x:
|
||||
/* First, the estimate must be rounded up. */
|
||||
addl $1,%edi
|
||||
adcl $0,%esi
|
||||
|
||||
sqrt_near_exact:
|
||||
/*
|
||||
* This is an easy case because x^1/2 is monotonic.
|
||||
* We need just find the square of our estimate, compare it
|
||||
* with the argument, and deduce whether our estimate is
|
||||
* above, below, or exact. We use the fact that the estimate
|
||||
* is known to be accurate to about 90 bits.
|
||||
*/
|
||||
movl %edi,%eax /* ls word of guess */
|
||||
mull %edi
|
||||
movl %edx,%ebx /* 2nd ls word of square */
|
||||
movl %eax,%ecx /* ls word of square */
|
||||
|
||||
movl %edi,%eax
|
||||
mull %esi
|
||||
addl %eax,%ebx
|
||||
addl %eax,%ebx
|
||||
|
||||
#ifdef PARANOID
|
||||
cmp $0xffffffb0,%ebx
|
||||
jb sqrt_near_exact_ok
|
||||
|
||||
cmp $0x00000050,%ebx
|
||||
ja sqrt_near_exact_ok
|
||||
|
||||
pushl EX_INTERNAL|0x214
|
||||
call EXCEPTION
|
||||
|
||||
sqrt_near_exact_ok:
|
||||
#endif PARANOID
|
||||
|
||||
or %ebx,%ebx
|
||||
js sqrt_near_exact_small
|
||||
|
||||
jnz sqrt_near_exact_large
|
||||
|
||||
or %ebx,%edx
|
||||
jnz sqrt_near_exact_large
|
||||
|
||||
/* Our estimate is exactly the right answer */
|
||||
xorl %eax,%eax
|
||||
jmp sqrt_round_result
|
||||
|
||||
sqrt_near_exact_small:
|
||||
/* Our estimate is too small */
|
||||
movl $0x000000ff,%eax
|
||||
jmp sqrt_round_result
|
||||
|
||||
sqrt_near_exact_large:
|
||||
/* Our estimate is too large, we need to decrement it */
|
||||
subl $1,%edi
|
||||
sbbl $0,%esi
|
||||
movl $0xffffff00,%eax
|
||||
jmp sqrt_round_result
|
||||
|
||||
|
||||
sqrt_get_more_precision:
|
||||
/* This case is almost the same as the above, except we start
|
||||
with an extra bit of precision in the estimate. */
|
||||
stc /* The extra bit. */
|
||||
rcll $1,%edi /* Shift the estimate left one bit */
|
||||
rcll $1,%esi
|
||||
|
||||
movl %edi,%eax /* ls word of guess */
|
||||
mull %edi
|
||||
movl %edx,%ebx /* 2nd ls word of square */
|
||||
movl %eax,%ecx /* ls word of square */
|
||||
|
||||
movl %edi,%eax
|
||||
mull %esi
|
||||
addl %eax,%ebx
|
||||
addl %eax,%ebx
|
||||
|
||||
/* Put our estimate back to its original value */
|
||||
stc /* The ms bit. */
|
||||
rcrl $1,%esi /* Shift the estimate left one bit */
|
||||
rcrl $1,%edi
|
||||
|
||||
#ifdef PARANOID
|
||||
cmp $0xffffff60,%ebx
|
||||
jb sqrt_more_prec_ok
|
||||
|
||||
cmp $0x000000a0,%ebx
|
||||
ja sqrt_more_prec_ok
|
||||
|
||||
pushl EX_INTERNAL|0x215
|
||||
call EXCEPTION
|
||||
|
||||
sqrt_more_prec_ok:
|
||||
#endif PARANOID
|
||||
|
||||
or %ebx,%ebx
|
||||
js sqrt_more_prec_small
|
||||
|
||||
jnz sqrt_more_prec_large
|
||||
|
||||
or %ebx,%ecx
|
||||
jnz sqrt_more_prec_large
|
||||
|
||||
/* Our estimate is exactly the right answer */
|
||||
movl $0x80000000,%eax
|
||||
jmp sqrt_round_result
|
||||
|
||||
sqrt_more_prec_small:
|
||||
/* Our estimate is too small */
|
||||
movl $0x800000ff,%eax
|
||||
jmp sqrt_round_result
|
||||
|
||||
sqrt_more_prec_large:
|
||||
/* Our estimate is too large */
|
||||
movl $0x7fffff00,%eax
|
||||
jmp sqrt_round_result
|
49
source/THIRDPARTY/linux-old/drivers/Makefile
Normal file
49
source/THIRDPARTY/linux-old/drivers/Makefile
Normal file
|
@ -0,0 +1,49 @@
|
|||
#
|
||||
# Makefile for the linux kernel device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
# Note 2! The CFLAGS definitions are now in the main makefile...
|
||||
|
||||
.S.s:
|
||||
$(CPP) -traditional $< -o $*.s
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) -S $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
SUBDIRS = block char net
|
||||
|
||||
ifdef CONFIG_MATH_EMULATION
|
||||
SUBDIRS := $(SUBDIRS) FPU-emu
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SCSI
|
||||
SUBDIRS := $(SUBDIRS) scsi
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SOUND
|
||||
SUBDIRS := $(SUBDIRS) sound
|
||||
endif
|
||||
|
||||
all: driversubdirs
|
||||
|
||||
driversubdirs: dummy
|
||||
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
|
||||
|
||||
dep:
|
||||
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
|
||||
|
||||
dummy:
|
||||
|
||||
#
|
||||
# include a dependency file if one exists
|
||||
#
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
include .depend
|
||||
endif
|
||||
|
72
source/THIRDPARTY/linux-old/drivers/block/Makefile
Normal file
72
source/THIRDPARTY/linux-old/drivers/block/Makefile
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# Makefile for the kernel block device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
# Note 2! The CFLAGS definition is now inherited from the
|
||||
# parent makefile.
|
||||
#
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) -S $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
#
|
||||
# Note : at this point, these files are compiled on all systems.
|
||||
# In the future, some of these should be built conditionally.
|
||||
#
|
||||
|
||||
OBJS := ll_rw_blk.o floppy.o ramdisk.o genhd.o
|
||||
SRCS := ll_rw_blk.c floppy.c ramdisk.c genhd.c
|
||||
|
||||
ifdef CONFIG_CDU31A
|
||||
OBJS := $(OBJS) cdu31a.o
|
||||
SRCS := $(SRCS) cdu31a.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MCD
|
||||
OBJS := $(OBJS) mcd.o
|
||||
SRCS := $(SRCS) mcd.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SBPCD
|
||||
OBJS := $(OBJS) sbpcd.o
|
||||
SRCS := $(SRCS) sbpcd.c
|
||||
ifdef PATCHLEVEL
|
||||
CFLAGS := $(CFLAGS) -DPATCHLEVEL=$(PATCHLEVEL)
|
||||
endif
|
||||
endif #CONFIG_SBPCD
|
||||
|
||||
ifdef CONFIG_BLK_DEV_HD
|
||||
OBJS := $(OBJS) hd.o
|
||||
SRCS := $(SRCS) hd.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_BLK_DEV_XD
|
||||
OBJS := $(OBJS) xd.o
|
||||
SRCS := $(SRCS) xd.c
|
||||
endif
|
||||
|
||||
all: block.a
|
||||
|
||||
block.a: $(OBJS)
|
||||
rm -f block.a
|
||||
$(AR) rcs block.a $(OBJS)
|
||||
sync
|
||||
|
||||
dep:
|
||||
$(CPP) -M $(SRCS) > .depend
|
||||
|
||||
dummy:
|
||||
|
||||
#
|
||||
# include a dependency file if one exists
|
||||
#
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
include .depend
|
||||
endif
|
214
source/THIRDPARTY/linux-old/drivers/block/README.sbpcd
Normal file
214
source/THIRDPARTY/linux-old/drivers/block/README.sbpcd
Normal file
|
@ -0,0 +1,214 @@
|
|||
This is release 1.2 of the SoundBlaster Pro (Matsushita, Kotobuki,
|
||||
Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux.
|
||||
|
||||
The driver is able to drive the whole family of IDE-style
|
||||
Matsushita/Kotobuki/Panasonic drives (the "double speed" versions
|
||||
like CR-562 and CR-563, too), and it will work with the soundcard
|
||||
interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with
|
||||
the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...).
|
||||
The interface type has to get configured, because the behavior
|
||||
is different.
|
||||
|
||||
The driver respects different drive firmware releases - my drive
|
||||
is a 2.11, but it should work with "old" drives <2.01 ... >3.00
|
||||
and with "new" drives (which count the releases around 0.75 or
|
||||
1.00).
|
||||
|
||||
Up to 4 drives are supported. CR-52x and CR-56x drives can be mixed,
|
||||
but the CR-521 ones are hard-wired to drive ID 0. The drives have
|
||||
to use different drive IDs, but the same controller (it will be a
|
||||
little bit harder to support up to four interface cards - but I plan
|
||||
to do it the day somebody wishes to connect a fifth drive).
|
||||
Each drive has to get a unique minor number (0...3), corresponding
|
||||
to it's drive ID. The drive IDs may be selected freely from 0 to 3 -
|
||||
they must not be in consecutive order.
|
||||
|
||||
If this driver doesn't work with your equipment, mail me a
|
||||
description, please.
|
||||
|
||||
The driver supports reading of data from the CD and playing of
|
||||
audio tracks. The audio part should run with WorkMan, xcdplayer,
|
||||
with the "non-X11" products CDplayer and WorkBone - tell me if
|
||||
it is not compatible with other software.
|
||||
|
||||
MultiSession is supported, "ManySession" (see below) alternatively.
|
||||
Photo CDs should work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm
|
||||
is a package to convert photo CD image files.
|
||||
|
||||
I did not have a chance to play with XA or mixed mode CDs yet.
|
||||
Send one over, if you would like sbpcd to support that.
|
||||
|
||||
The transfer rate will reach 150 kB/sec with standard drives and
|
||||
the full 300 kB/sec with double-speed drives.
|
||||
|
||||
This release is part of the standard kernel and consists of
|
||||
- this README file
|
||||
- the driver file linux/drivers/block/sbpcd.c
|
||||
- the header file linux/include/linux/sbpcd.h.
|
||||
|
||||
|
||||
To install:
|
||||
-----------
|
||||
|
||||
1. Setup your hardware parameters. Though the driver does "auto-probing"
|
||||
now, this step is recommended for every-day use.
|
||||
a. Go into /usr/src/linux/include/linux/sbpcd.h and configure
|
||||
it for your hardware (near the beginning):
|
||||
a1. Set it up for the appropriate type of interface board.
|
||||
Most "compatible" sound boards (for example "Highscreen",
|
||||
"SoundFX" and "Galaxy") need the "SBPRO 0" setup. The
|
||||
"no-sound" board from OmniCd needs the "SBPRO 1" setup.
|
||||
sbpcd.c holds some examples in it's auto-probe list.
|
||||
a2. Tell the address of your CDROM_PORT.
|
||||
b. Additionally for 2.a1 and 2.a2, the setup may be done during
|
||||
boot time (via the "kernel command line" or "LILO option"):
|
||||
sbpcd=0x230,SoundBlaster
|
||||
or
|
||||
sbpcd=0x320,LaserMate
|
||||
(these strings are case sensitive!).
|
||||
|
||||
2. Do a "make config" and select "yes" for Matsushita CD-ROM
|
||||
support and for ISO9660 FileSystem support.
|
||||
SCSI and/or SCSI CD-ROM support is not needed.
|
||||
|
||||
3. Then do a "make dep", then make the kernel image ("make zlilo"
|
||||
or else).
|
||||
|
||||
4. Make the device file(s). The driver uses definitely and exclusive
|
||||
the MAJOR 25, so do
|
||||
|
||||
mknod /dev/sbpcd b 25 0 (if you have only drive #0)
|
||||
and/or
|
||||
mknod /dev/sbpcd0 b 25 0
|
||||
mknod /dev/sbpcd1 b 25 1
|
||||
mknod /dev/sbpcd2 b 25 2
|
||||
mknod /dev/sbpcd3 b 25 3
|
||||
|
||||
to make the node(s).
|
||||
Take care that you create a node with the same MINOR as your drive
|
||||
id is. So, if the DOS driver tells you have drive id #3, you have to
|
||||
mknod /dev/<any_name> b 25 3
|
||||
|
||||
If you further make a link like
|
||||
ln -s sbpcd /dev/cdrom
|
||||
you can use the name /dev/cdrom, too.
|
||||
|
||||
5. Reboot with the new kernel.
|
||||
|
||||
You should now be able to do "mount -t iso9660 /dev/sbpcd /mnt"
|
||||
and see the contents of your CD in the /mnt directory, and/or
|
||||
hear music with "workman -c /dev/sbpcd &".
|
||||
|
||||
|
||||
Things of interest:
|
||||
-------------------
|
||||
|
||||
The driver is configured to try the SoundBlaster Pro type of
|
||||
interface at I/O port 0x0230 first. If this is not appropriate,
|
||||
sbpcd.h should get changed (you will find the right place -
|
||||
just at the beginning).
|
||||
|
||||
No DMA and no IRQ is used, so the IRQ adjusting is not necessary,
|
||||
and the IRQ line stays free for the SB Pro sound drivers.
|
||||
|
||||
To reduce or increase the amount of kernel messages, edit
|
||||
sbpcd.c and change the initialization of the variable
|
||||
"sbpcd_debug". This is the way to get rid of the initial
|
||||
warning message block, too.
|
||||
|
||||
With "#define MANY_SESSION 1" (sbpcd.c), the driver can use
|
||||
"many-session" CDs. This will work only with "new" drives like
|
||||
CR-562 or CR-563. That is NOT multisession - it is a CD
|
||||
with multiple independent sessions, each containing block
|
||||
addresses as if it were the only session. With this feature
|
||||
enabled, the driver will read the LAST session. Without it,
|
||||
the FIRST session gets read.
|
||||
If you would like the support of reading "in-between" sessions,
|
||||
drop me a mail and some food for the soul. :-)
|
||||
Those "many-session" CDs can get made by CDROM writers like
|
||||
Philips CDD 521.
|
||||
With this feature enabled, it is impossible to read true
|
||||
multisession CDs.
|
||||
|
||||
|
||||
Auto-probing at boot time:
|
||||
--------------------------
|
||||
|
||||
The driver does auto-probing at all well-known interface card
|
||||
addresses now. The idea to do that came from Adam J. Richter
|
||||
(YGGDRASIL).
|
||||
|
||||
This auto-probing looks first at the configured address resp.
|
||||
the address submitted by the kernel command line. With this,
|
||||
it is possible to use this driver within installation boot
|
||||
floppies, and for any non-standard address, too.
|
||||
|
||||
Auto-probing will make an assumption about the interface type
|
||||
("SBPRO" or not), based upon the address. That assumption may
|
||||
be wrong (initialization will be o.k., but you will get I/O
|
||||
errors during mount). In that case, use the "kernel command
|
||||
line" feature and specify address & type at boot time to find
|
||||
out the right setup.
|
||||
|
||||
SBPCD's auto-probing happens before the initialization of the
|
||||
net drivers. That makes a hang possible if an ethernet card
|
||||
gets touched.
|
||||
|
||||
For every-day use, address and type should get configured
|
||||
within sbpcd.h. That will stop the auto-probing due to success
|
||||
with the first try.
|
||||
|
||||
|
||||
Setting up address and interface type:
|
||||
--------------------------------------
|
||||
|
||||
If your I/O port address is not 0x0230 or if you use a "no-sound"
|
||||
interface other than OmniCD, you have to look for the #defines
|
||||
near the beginning of sbpcd.h and configure them: set SBPRO to
|
||||
0 or 1, and change CDROM_PORT to the address of your CDROM I/O port.
|
||||
|
||||
Most of the "SoundBlaster compatible" cards behave like the
|
||||
no-sound interfaces!
|
||||
|
||||
With "original" SB Pro cards, an initial setting of CD_volume
|
||||
through the sound cards MIXER register gets done. That happens
|
||||
at the end of "sbpcd_init". If you are using a "compatible"
|
||||
sound card of type "LaserMate", you can change that code to get
|
||||
it done with your card, too...
|
||||
|
||||
|
||||
Using audio CDs:
|
||||
----------------
|
||||
|
||||
Workman, WorkBone, xcdplayer and cdplayer should work good now,
|
||||
even with the double-speed drives.
|
||||
|
||||
The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer
|
||||
wants "/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate
|
||||
links for using them without the need of supplying parameters.
|
||||
|
||||
|
||||
Known problems:
|
||||
---------------
|
||||
|
||||
Currently, the detection of disk change or removal does not
|
||||
work as good as it should.
|
||||
|
||||
Further, I do not know if this driver can live together with a
|
||||
SCSI CD-ROM driver and/or device, but I hope so.
|
||||
|
||||
|
||||
|
||||
Bug reports, comments, wishes, donations (technical information
|
||||
is a donation, too :-) etc. to
|
||||
emoenke@gwdg.de
|
||||
or to eberhard_moenkeberg@rollo.central.de
|
||||
or to my FIDO address: Eberhard Moenkeberg, 2:2437/210.27
|
||||
|
||||
|
||||
SnailMail address, preferable for CD editors if they want to submit
|
||||
a free "cooperation" copy:
|
||||
Eberhard Moenkeberg
|
||||
Reinholdstr. 14
|
||||
D-37083 Goettingen
|
||||
Germany
|
310
source/THIRDPARTY/linux-old/drivers/block/blk.h
Normal file
310
source/THIRDPARTY/linux-old/drivers/block/blk.h
Normal file
|
@ -0,0 +1,310 @@
|
|||
#ifndef _BLK_H
|
||||
#define _BLK_H
|
||||
|
||||
#include <linux/major.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/locks.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
/*
|
||||
* NR_REQUEST is the number of entries in the request-queue.
|
||||
* NOTE that writes may use only the low 2/3 of these: reads
|
||||
* take precedence.
|
||||
*
|
||||
* 32 seems to be a reasonable number: enough to get some benefit
|
||||
* from the elevator-mechanism, but not so much as to lock a lot of
|
||||
* buffers when they are in the queue. 64 seems to be too many (easily
|
||||
* long pauses in reading when heavy writing/syncing is going on)
|
||||
*/
|
||||
#define NR_REQUEST 64
|
||||
|
||||
/*
|
||||
* Ok, this is an expanded form so that we can use the same
|
||||
* request for paging requests when that is implemented. In
|
||||
* paging, 'bh' is NULL, and 'waiting' is used to wait for
|
||||
* read/write completion.
|
||||
*/
|
||||
struct request {
|
||||
int dev; /* -1 if no request */
|
||||
int cmd; /* READ or WRITE */
|
||||
int errors;
|
||||
unsigned long sector;
|
||||
unsigned long nr_sectors;
|
||||
unsigned long current_nr_sectors;
|
||||
char * buffer;
|
||||
struct task_struct * waiting;
|
||||
struct buffer_head * bh;
|
||||
struct buffer_head * bhtail;
|
||||
struct request * next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is used in the elevator algorithm: Note that
|
||||
* reads always go before writes. This is natural: reads
|
||||
* are much more time-critical than writes.
|
||||
*/
|
||||
#define IN_ORDER(s1,s2) \
|
||||
((s1)->cmd < (s2)->cmd || ((s1)->cmd == (s2)->cmd && \
|
||||
((s1)->dev < (s2)->dev || (((s1)->dev == (s2)->dev && \
|
||||
(s1)->sector < (s2)->sector)))))
|
||||
|
||||
struct blk_dev_struct {
|
||||
void (*request_fn)(void);
|
||||
struct request * current_request;
|
||||
};
|
||||
|
||||
|
||||
struct sec_size {
|
||||
unsigned block_size;
|
||||
unsigned block_size_bits;
|
||||
};
|
||||
|
||||
/*
|
||||
* These will have to be changed to be aware of different buffer
|
||||
* sizes etc.. It actually needs a major cleanup.
|
||||
*/
|
||||
#define SECTOR_MASK (blksize_size[MAJOR_NR] && \
|
||||
blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] ? \
|
||||
((blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] >> 9) - 1) : \
|
||||
((BLOCK_SIZE >> 9) - 1))
|
||||
|
||||
#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
|
||||
|
||||
extern struct sec_size * blk_sec[MAX_BLKDEV];
|
||||
extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
|
||||
extern struct wait_queue * wait_for_request;
|
||||
extern void resetup_one_dev(struct gendisk *dev, int drive);
|
||||
|
||||
extern int * blk_size[MAX_BLKDEV];
|
||||
|
||||
extern int * blksize_size[MAX_BLKDEV];
|
||||
|
||||
extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
|
||||
extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end);
|
||||
extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end);
|
||||
extern int is_read_only(int dev);
|
||||
extern void set_device_ro(int dev,int flag);
|
||||
|
||||
extern void rd_load(void);
|
||||
extern long rd_init(long mem_start, int length);
|
||||
extern int ramdisk_size;
|
||||
|
||||
extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
|
||||
|
||||
#define RO_IOCTLS(dev,where) \
|
||||
case BLKROSET: if (!suser()) return -EPERM; \
|
||||
set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
|
||||
case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \
|
||||
if (!__err) put_fs_long(is_read_only(dev),(long *) (where)); return __err; }
|
||||
|
||||
#ifdef MAJOR_NR
|
||||
|
||||
/*
|
||||
* Add entries as needed. Currently the only block devices
|
||||
* supported are hard-disks and floppies.
|
||||
*/
|
||||
|
||||
#if (MAJOR_NR == MEM_MAJOR)
|
||||
|
||||
/* ram disk */
|
||||
#define DEVICE_NAME "ramdisk"
|
||||
#define DEVICE_REQUEST do_rd_request
|
||||
#define DEVICE_NR(device) ((device) & 7)
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == FLOPPY_MAJOR)
|
||||
|
||||
static void floppy_on(unsigned int nr);
|
||||
static void floppy_off(unsigned int nr);
|
||||
|
||||
#define DEVICE_NAME "floppy"
|
||||
#define DEVICE_INTR do_floppy
|
||||
#define DEVICE_REQUEST do_fd_request
|
||||
#define DEVICE_NR(device) ((device) & 3)
|
||||
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
|
||||
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
|
||||
|
||||
#elif (MAJOR_NR == HD_MAJOR)
|
||||
|
||||
/* harddisk: timeout is 6 seconds.. */
|
||||
#define DEVICE_NAME "harddisk"
|
||||
#define DEVICE_INTR do_hd
|
||||
#define DEVICE_TIMEOUT HD_TIMER
|
||||
#define TIMEOUT_VALUE 600
|
||||
#define DEVICE_REQUEST do_hd_request
|
||||
#define DEVICE_NR(device) (MINOR(device)>>6)
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == SCSI_DISK_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "scsidisk"
|
||||
#define DEVICE_INTR do_sd
|
||||
#define TIMEOUT_VALUE 200
|
||||
#define DEVICE_REQUEST do_sd_request
|
||||
#define DEVICE_NR(device) (MINOR(device) >> 4)
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == SCSI_TAPE_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "scsitape"
|
||||
#define DEVICE_INTR do_st
|
||||
#define DEVICE_NR(device) (MINOR(device))
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == SCSI_CDROM_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "CD-ROM"
|
||||
#define DEVICE_INTR do_sr
|
||||
#define DEVICE_REQUEST do_sr_request
|
||||
#define DEVICE_NR(device) (MINOR(device))
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == XT_DISK_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "xt disk"
|
||||
#define DEVICE_REQUEST do_xd_request
|
||||
#define DEVICE_NR(device) (MINOR(device) >> 6)
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "CDU31A"
|
||||
#define DEVICE_REQUEST do_cdu31a_request
|
||||
#define DEVICE_NR(device) (MINOR(device))
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "Mitsumi CD-ROM"
|
||||
/* #define DEVICE_INTR do_mcd */
|
||||
#define DEVICE_REQUEST do_mcd_request
|
||||
#define DEVICE_NR(device) (MINOR(device))
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
|
||||
|
||||
#define DEVICE_NAME "Matsushita CD-ROM"
|
||||
#define DEVICE_REQUEST do_sbpcd_request
|
||||
#define DEVICE_NR(device) (MINOR(device))
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#else
|
||||
|
||||
#error "unknown blk device"
|
||||
|
||||
#endif
|
||||
|
||||
#if (MAJOR_NR != SCSI_TAPE_MAJOR)
|
||||
|
||||
#ifndef CURRENT
|
||||
#define CURRENT (blk_dev[MAJOR_NR].current_request)
|
||||
#endif
|
||||
|
||||
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
|
||||
|
||||
#ifdef DEVICE_INTR
|
||||
void (*DEVICE_INTR)(void) = NULL;
|
||||
#endif
|
||||
#ifdef DEVICE_TIMEOUT
|
||||
|
||||
#define SET_TIMER \
|
||||
((timer_table[DEVICE_TIMEOUT].expires = jiffies + TIMEOUT_VALUE), \
|
||||
(timer_active |= 1<<DEVICE_TIMEOUT))
|
||||
|
||||
#define CLEAR_TIMER \
|
||||
timer_active &= ~(1<<DEVICE_TIMEOUT)
|
||||
|
||||
#define SET_INTR(x) \
|
||||
if ((DEVICE_INTR = (x)) != NULL) \
|
||||
SET_TIMER; \
|
||||
else \
|
||||
CLEAR_TIMER;
|
||||
|
||||
#else
|
||||
|
||||
#define SET_INTR(x) (DEVICE_INTR = (x))
|
||||
|
||||
#endif
|
||||
static void (DEVICE_REQUEST)(void);
|
||||
|
||||
/* end_request() - SCSI devices have their own version */
|
||||
|
||||
#if ! SCSI_MAJOR(MAJOR_NR)
|
||||
|
||||
static void end_request(int uptodate)
|
||||
{
|
||||
struct request * req;
|
||||
struct buffer_head * bh;
|
||||
struct task_struct * p;
|
||||
|
||||
req = CURRENT;
|
||||
req->errors = 0;
|
||||
if (!uptodate) {
|
||||
printk(DEVICE_NAME " I/O error\n");
|
||||
printk("dev %04lX, sector %lu\n",
|
||||
(unsigned long)req->dev, req->sector);
|
||||
req->nr_sectors--;
|
||||
req->nr_sectors &= ~SECTOR_MASK;
|
||||
req->sector += (BLOCK_SIZE / 512);
|
||||
req->sector &= ~SECTOR_MASK;
|
||||
}
|
||||
|
||||
if ((bh = req->bh) != NULL) {
|
||||
req->bh = bh->b_reqnext;
|
||||
bh->b_reqnext = NULL;
|
||||
bh->b_uptodate = uptodate;
|
||||
unlock_buffer(bh);
|
||||
if ((bh = req->bh) != NULL) {
|
||||
req->current_nr_sectors = bh->b_size >> 9;
|
||||
if (req->nr_sectors < req->current_nr_sectors) {
|
||||
req->nr_sectors = req->current_nr_sectors;
|
||||
printk("end_request: buffer-list destroyed\n");
|
||||
}
|
||||
req->buffer = bh->b_data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
DEVICE_OFF(req->dev);
|
||||
CURRENT = req->next;
|
||||
if ((p = req->waiting) != NULL) {
|
||||
req->waiting = NULL;
|
||||
p->state = TASK_RUNNING;
|
||||
if (p->counter > current->counter)
|
||||
need_resched = 1;
|
||||
}
|
||||
req->dev = -1;
|
||||
wake_up(&wait_for_request);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEVICE_INTR
|
||||
#define CLEAR_INTR SET_INTR(NULL)
|
||||
#else
|
||||
#define CLEAR_INTR
|
||||
#endif
|
||||
|
||||
#define INIT_REQUEST \
|
||||
if (!CURRENT) {\
|
||||
CLEAR_INTR; \
|
||||
return; \
|
||||
} \
|
||||
if (MAJOR(CURRENT->dev) != MAJOR_NR) \
|
||||
panic(DEVICE_NAME ": request list destroyed"); \
|
||||
if (CURRENT->bh) { \
|
||||
if (!CURRENT->bh->b_lock) \
|
||||
panic(DEVICE_NAME ": block not locked"); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
1852
source/THIRDPARTY/linux-old/drivers/block/cdu31a.c
Normal file
1852
source/THIRDPARTY/linux-old/drivers/block/cdu31a.c
Normal file
File diff suppressed because it is too large
Load diff
1387
source/THIRDPARTY/linux-old/drivers/block/floppy.c
Normal file
1387
source/THIRDPARTY/linux-old/drivers/block/floppy.c
Normal file
File diff suppressed because it is too large
Load diff
216
source/THIRDPARTY/linux-old/drivers/block/genhd.c
Normal file
216
source/THIRDPARTY/linux-old/drivers/block/genhd.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Code extracted from
|
||||
* linux/kernel/hd.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
|
||||
* in the early extended-partition checks and added DM partitions
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
struct gendisk *gendisk_head = NULL;
|
||||
|
||||
static int current_minor = 0;
|
||||
extern int *blk_size[];
|
||||
extern void rd_load(void);
|
||||
extern int ramdisk_size;
|
||||
|
||||
/*
|
||||
* Create devices for each logical partition in an extended partition.
|
||||
* The logical partitions form a linked list, with each entry being
|
||||
* a partition table with two entries. The first entry
|
||||
* is the real data partition (with a start relative to the partition
|
||||
* table start). The second is a pointer to the next logical partition
|
||||
* (with a start relative to the entire extended partition).
|
||||
* We do not create a Linux partition for the partition tables, but
|
||||
* only for the actual data partitions.
|
||||
*/
|
||||
|
||||
static void extended_partition(struct gendisk *hd, int dev)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
struct partition *p;
|
||||
unsigned long first_sector, this_sector;
|
||||
int mask = (1 << hd->minor_shift) - 1;
|
||||
|
||||
first_sector = hd->part[MINOR(dev)].start_sect;
|
||||
this_sector = first_sector;
|
||||
|
||||
while (1) {
|
||||
if ((current_minor & mask) >= (4 + hd->max_p))
|
||||
return;
|
||||
if (!(bh = bread(dev,0,1024)))
|
||||
return;
|
||||
/*
|
||||
* This block is from a device that we're about to stomp on.
|
||||
* So make sure nobody thinks this block is usable.
|
||||
*/
|
||||
bh->b_dirt=0;
|
||||
bh->b_uptodate=0;
|
||||
if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
|
||||
p = (struct partition *) (0x1BE + bh->b_data);
|
||||
/*
|
||||
* Process the first entry, which should be the real
|
||||
* data partition.
|
||||
*/
|
||||
if (p->sys_ind == EXTENDED_PARTITION ||
|
||||
!(hd->part[current_minor].nr_sects = p->nr_sects))
|
||||
goto done; /* shouldn't happen */
|
||||
hd->part[current_minor].start_sect = this_sector + p->start_sect;
|
||||
printk(" %s%c%d", hd->major_name,
|
||||
'a'+(current_minor >> hd->minor_shift),
|
||||
mask & current_minor);
|
||||
current_minor++;
|
||||
p++;
|
||||
/*
|
||||
* Process the second entry, which should be a link
|
||||
* to the next logical partition. Create a minor
|
||||
* for this just long enough to get the next partition
|
||||
* table. The minor will be reused for the real
|
||||
* data partition.
|
||||
*/
|
||||
if (p->sys_ind != EXTENDED_PARTITION ||
|
||||
!(hd->part[current_minor].nr_sects = p->nr_sects))
|
||||
goto done; /* no more logicals in this partition */
|
||||
hd->part[current_minor].start_sect = first_sector + p->start_sect;
|
||||
this_sector = first_sector + p->start_sect;
|
||||
dev = ((hd->major) << 8) | current_minor;
|
||||
brelse(bh);
|
||||
} else
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
static void check_partition(struct gendisk *hd, unsigned int dev)
|
||||
{
|
||||
static int first_time = 1;
|
||||
int i, minor = current_minor;
|
||||
struct buffer_head *bh;
|
||||
struct partition *p;
|
||||
unsigned long first_sector;
|
||||
int mask = (1 << hd->minor_shift) - 1;
|
||||
|
||||
if (first_time)
|
||||
printk("Partition check:\n");
|
||||
first_time = 0;
|
||||
first_sector = hd->part[MINOR(dev)].start_sect;
|
||||
if (!(bh = bread(dev,0,1024))) {
|
||||
printk(" unable to read partition table of device %04x\n",dev);
|
||||
return;
|
||||
}
|
||||
printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
|
||||
current_minor += 4; /* first "extra" minor */
|
||||
if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
|
||||
p = (struct partition *) (0x1BE + bh->b_data);
|
||||
for (i=1 ; i<=4 ; minor++,i++,p++) {
|
||||
if (!(hd->part[minor].nr_sects = p->nr_sects))
|
||||
continue;
|
||||
hd->part[minor].start_sect = first_sector + p->start_sect;
|
||||
printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), i);
|
||||
if ((current_minor & 0x3f) >= 60)
|
||||
continue;
|
||||
if (p->sys_ind == EXTENDED_PARTITION) {
|
||||
printk(" <");
|
||||
extended_partition(hd, (hd->major << 8) | minor);
|
||||
printk(" >");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* check for Disk Manager partition table
|
||||
*/
|
||||
if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
|
||||
p = (struct partition *) (0x1BE + bh->b_data);
|
||||
for (i = 4 ; i < 16 ; i++, current_minor++) {
|
||||
p--;
|
||||
if ((current_minor & mask) >= mask-2)
|
||||
break;
|
||||
if (!(p->start_sect && p->nr_sects))
|
||||
continue;
|
||||
hd->part[current_minor].start_sect = p->start_sect;
|
||||
hd->part[current_minor].nr_sects = p->nr_sects;
|
||||
printk(" %s%c%d", hd->major_name,
|
||||
'a'+(current_minor >> hd->minor_shift),
|
||||
current_minor & mask);
|
||||
}
|
||||
}
|
||||
} else
|
||||
printk(" bad partition table");
|
||||
printk("\n");
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
/* This function is used to re-read partition tables for removable disks.
|
||||
Much of the cleanup from the old partition tables should have already been
|
||||
done */
|
||||
|
||||
/* This function will re-read the partition tables for a given device,
|
||||
and set things back up again. There are some important caveats,
|
||||
however. You must ensure that no one is using the device, and no one
|
||||
can start using the device while this function is being executed. */
|
||||
|
||||
void resetup_one_dev(struct gendisk *dev, int drive)
|
||||
{
|
||||
int i;
|
||||
int start = drive<<dev->minor_shift;
|
||||
int j = start + dev->max_p;
|
||||
int major = dev->major << 8;
|
||||
|
||||
current_minor = 1+(drive<<dev->minor_shift);
|
||||
check_partition(dev, major+(drive<<dev->minor_shift));
|
||||
|
||||
for (i=start ; i < j ; i++)
|
||||
dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
|
||||
}
|
||||
|
||||
static void setup_dev(struct gendisk *dev)
|
||||
{
|
||||
int i;
|
||||
int j = dev->max_nr * dev->max_p;
|
||||
int major = dev->major << 8;
|
||||
int drive;
|
||||
|
||||
|
||||
for (i = 0 ; i < j; i++) {
|
||||
dev->part[i].start_sect = 0;
|
||||
dev->part[i].nr_sects = 0;
|
||||
}
|
||||
dev->init();
|
||||
for (drive=0 ; drive<dev->nr_real ; drive++) {
|
||||
current_minor = 1+(drive<<dev->minor_shift);
|
||||
check_partition(dev, major+(drive<<dev->minor_shift));
|
||||
}
|
||||
for (i=0 ; i < j ; i++)
|
||||
dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
|
||||
blk_size[dev->major] = dev->sizes;
|
||||
}
|
||||
|
||||
/* This may be used only once, enforced by 'static int callable' */
|
||||
asmlinkage int sys_setup(void * BIOS)
|
||||
{
|
||||
static int callable = 1;
|
||||
struct gendisk *p;
|
||||
int nr=0;
|
||||
|
||||
if (!callable)
|
||||
return -1;
|
||||
callable = 0;
|
||||
|
||||
for (p = gendisk_head ; p ; p=p->next) {
|
||||
setup_dev(p);
|
||||
nr += p->nr_real;
|
||||
}
|
||||
|
||||
if (ramdisk_size)
|
||||
rd_load();
|
||||
mount_root();
|
||||
return (0);
|
||||
}
|
797
source/THIRDPARTY/linux-old/drivers/block/hd.c
Normal file
797
source/THIRDPARTY/linux-old/drivers/block/hd.c
Normal file
|
@ -0,0 +1,797 @@
|
|||
/*
|
||||
* linux/kernel/hd.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the low-level hd interrupt support. It traverses the
|
||||
* request-list, using interrupts to jump between functions. As
|
||||
* all the functions are called within interrupts, we may not
|
||||
* sleep. Special care is recommended.
|
||||
*
|
||||
* modified by Drew Eckhardt to check nr of hd's from the CMOS.
|
||||
*
|
||||
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
|
||||
* in the early extended-partition checks and added DM partitions
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/config.h>
|
||||
|
||||
#define REALLY_SLOW_IO
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define MAJOR_NR HD_MAJOR
|
||||
#include "blk.h"
|
||||
|
||||
#define HD_IRQ 14
|
||||
|
||||
static int revalidate_hddisk(int, int);
|
||||
|
||||
static inline unsigned char CMOS_READ(unsigned char addr)
|
||||
{
|
||||
outb_p(addr,0x70);
|
||||
return inb_p(0x71);
|
||||
}
|
||||
|
||||
#define HD_DELAY 0
|
||||
|
||||
#define MAX_ERRORS 16 /* Max read/write errors/sector */
|
||||
#define RESET_FREQ 8 /* Reset controller every 8th retry */
|
||||
#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
|
||||
#define MAX_HD 2
|
||||
|
||||
static void recal_intr(void);
|
||||
static void bad_rw_intr(void);
|
||||
|
||||
static char recalibrate[ MAX_HD ] = { 0, };
|
||||
static int access_count[MAX_HD] = {0, };
|
||||
static char busy[MAX_HD] = {0, };
|
||||
static struct wait_queue * busy_wait = NULL;
|
||||
|
||||
static int reset = 0;
|
||||
static int hd_error = 0;
|
||||
|
||||
#if (HD_DELAY > 0)
|
||||
unsigned long last_req, read_timer();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This struct defines the HD's and their types.
|
||||
*/
|
||||
struct hd_i_struct {
|
||||
unsigned int head,sect,cyl,wpcom,lzone,ctl;
|
||||
};
|
||||
#ifdef HD_TYPE
|
||||
struct hd_i_struct hd_info[] = { HD_TYPE };
|
||||
static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
|
||||
#else
|
||||
struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
|
||||
static int NR_HD = 0;
|
||||
#endif
|
||||
|
||||
static struct hd_struct hd[MAX_HD<<6]={{0,0},};
|
||||
static int hd_sizes[MAX_HD<<6] = {0, };
|
||||
static int hd_blocksizes[MAX_HD<<6] = {0, };
|
||||
|
||||
#if (HD_DELAY > 0)
|
||||
unsigned long read_timer(void)
|
||||
{
|
||||
unsigned long t;
|
||||
int i;
|
||||
|
||||
cli();
|
||||
t = jiffies * 11932;
|
||||
outb_p(0, 0x43);
|
||||
i = inb_p(0x40);
|
||||
i |= inb(0x40) << 8;
|
||||
sti();
|
||||
return(t - i);
|
||||
}
|
||||
#endif
|
||||
|
||||
void hd_setup(char *str, int *ints)
|
||||
{
|
||||
int hdind = 0;
|
||||
|
||||
if (ints[0] != 3)
|
||||
return;
|
||||
if (hd_info[0].head != 0)
|
||||
hdind=1;
|
||||
hd_info[hdind].head = ints[2];
|
||||
hd_info[hdind].sect = ints[3];
|
||||
hd_info[hdind].cyl = ints[1];
|
||||
hd_info[hdind].wpcom = 0;
|
||||
hd_info[hdind].lzone = ints[1];
|
||||
hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
|
||||
NR_HD = hdind+1;
|
||||
}
|
||||
|
||||
static int win_result(void)
|
||||
{
|
||||
int i=inb_p(HD_STATUS);
|
||||
|
||||
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
|
||||
== (READY_STAT | SEEK_STAT)) {
|
||||
hd_error = 0;
|
||||
return 0; /* ok */
|
||||
}
|
||||
printk("HD: win_result: status = 0x%02x\n",i);
|
||||
if (i&1) {
|
||||
hd_error = inb(HD_ERROR);
|
||||
printk("HD: win_result: error = 0x%02x\n",hd_error);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int controller_busy(void);
|
||||
static int status_ok(void);
|
||||
|
||||
static int controller_ready(unsigned int drive, unsigned int head)
|
||||
{
|
||||
int retry = 100;
|
||||
|
||||
do {
|
||||
if (controller_busy() & BUSY_STAT)
|
||||
return 0;
|
||||
outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
|
||||
if (status_ok())
|
||||
return 1;
|
||||
} while (--retry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_ok(void)
|
||||
{
|
||||
unsigned char status = inb_p(HD_STATUS);
|
||||
|
||||
if (status & BUSY_STAT)
|
||||
return 1;
|
||||
if (status & WRERR_STAT)
|
||||
return 0;
|
||||
if (!(status & READY_STAT))
|
||||
return 0;
|
||||
if (!(status & SEEK_STAT))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int controller_busy(void)
|
||||
{
|
||||
int retries = 100000;
|
||||
unsigned char status;
|
||||
|
||||
do {
|
||||
status = inb_p(HD_STATUS);
|
||||
} while ((status & BUSY_STAT) && --retries);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
|
||||
unsigned int head,unsigned int cyl,unsigned int cmd,
|
||||
void (*intr_addr)(void))
|
||||
{
|
||||
unsigned short port;
|
||||
|
||||
if (drive>1 || head>15)
|
||||
panic("Trying to write bad sector");
|
||||
#if (HD_DELAY > 0)
|
||||
while (read_timer() - last_req < HD_DELAY)
|
||||
/* nothing */;
|
||||
#endif
|
||||
if (reset)
|
||||
return;
|
||||
if (!controller_ready(drive, head)) {
|
||||
reset = 1;
|
||||
return;
|
||||
}
|
||||
SET_INTR(intr_addr);
|
||||
outb_p(hd_info[drive].ctl,HD_CMD);
|
||||
port=HD_DATA;
|
||||
outb_p(hd_info[drive].wpcom>>2,++port);
|
||||
outb_p(nsect,++port);
|
||||
outb_p(sect,++port);
|
||||
outb_p(cyl,++port);
|
||||
outb_p(cyl>>8,++port);
|
||||
outb_p(0xA0|(drive<<4)|head,++port);
|
||||
outb_p(cmd,++port);
|
||||
}
|
||||
|
||||
static int drive_busy(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char c;
|
||||
|
||||
for (i = 0; i < 500000 ; i++) {
|
||||
c = inb_p(HD_STATUS);
|
||||
c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
|
||||
if (c == (READY_STAT | SEEK_STAT))
|
||||
return 0;
|
||||
}
|
||||
printk("HD controller times out, status = 0x%02x\n",c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void reset_controller(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_DEBUG "HD-controller reset\n");
|
||||
outb_p(4,HD_CMD);
|
||||
for(i = 0; i < 1000; i++) nop();
|
||||
outb(hd_info[0].ctl & 0x0f ,HD_CMD);
|
||||
if (drive_busy())
|
||||
printk("HD-controller still busy\n");
|
||||
if ((hd_error = inb(HD_ERROR)) != 1)
|
||||
printk("HD-controller reset failed: %02x\n",hd_error);
|
||||
}
|
||||
|
||||
static void reset_hd(void)
|
||||
{
|
||||
static int i;
|
||||
|
||||
repeat:
|
||||
if (reset) {
|
||||
reset = 0;
|
||||
i = -1;
|
||||
reset_controller();
|
||||
} else if (win_result()) {
|
||||
bad_rw_intr();
|
||||
if (reset)
|
||||
goto repeat;
|
||||
}
|
||||
i++;
|
||||
if (i < NR_HD) {
|
||||
hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
|
||||
hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
} else
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, don't know what to do with the unexpected interrupts: on some machines
|
||||
* doing a reset and a retry seems to result in an eternal loop. Right now I
|
||||
* ignore it, and just set the timeout.
|
||||
*/
|
||||
void unexpected_hd_interrupt(void)
|
||||
{
|
||||
sti();
|
||||
printk(KERN_DEBUG "Unexpected HD interrupt\n");
|
||||
SET_TIMER;
|
||||
}
|
||||
|
||||
/*
|
||||
* bad_rw_intr() now tries to be a bit smarter and does things
|
||||
* according to the error returned by the controller.
|
||||
* -Mika Liljeberg (liljeber@cs.Helsinki.FI)
|
||||
*/
|
||||
static void bad_rw_intr(void)
|
||||
{
|
||||
int dev;
|
||||
|
||||
if (!CURRENT)
|
||||
return;
|
||||
dev = MINOR(CURRENT->dev) >> 6;
|
||||
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
|
||||
end_request(0);
|
||||
recalibrate[dev] = 1;
|
||||
} else if (CURRENT->errors % RESET_FREQ == 0)
|
||||
reset = 1;
|
||||
else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
|
||||
recalibrate[dev] = 1;
|
||||
/* Otherwise just retry */
|
||||
}
|
||||
|
||||
static inline int wait_DRQ(void)
|
||||
{
|
||||
int retries = 100000;
|
||||
|
||||
while (--retries > 0)
|
||||
if (inb_p(HD_STATUS) & DRQ_STAT)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
|
||||
#define STAT_OK (READY_STAT | SEEK_STAT)
|
||||
|
||||
static void read_intr(void)
|
||||
{
|
||||
int i;
|
||||
int retries = 100000;
|
||||
|
||||
do {
|
||||
i = (unsigned) inb_p(HD_STATUS);
|
||||
if (i & BUSY_STAT)
|
||||
continue;
|
||||
if ((i & STAT_MASK) != STAT_OK)
|
||||
break;
|
||||
if (i & DRQ_STAT)
|
||||
goto ok_to_read;
|
||||
} while (--retries > 0);
|
||||
sti();
|
||||
printk("HD: read_intr: status = 0x%02x\n",i);
|
||||
if (i & ERR_STAT) {
|
||||
hd_error = (unsigned) inb(HD_ERROR);
|
||||
printk("HD: read_intr: error = 0x%02x\n",hd_error);
|
||||
}
|
||||
bad_rw_intr();
|
||||
cli();
|
||||
do_hd_request();
|
||||
return;
|
||||
ok_to_read:
|
||||
insw(HD_DATA,CURRENT->buffer,256);
|
||||
CURRENT->errors = 0;
|
||||
CURRENT->buffer += 512;
|
||||
CURRENT->sector++;
|
||||
i = --CURRENT->nr_sectors;
|
||||
--CURRENT->current_nr_sectors;
|
||||
#ifdef DEBUG
|
||||
printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
|
||||
MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
|
||||
buffer);
|
||||
#endif
|
||||
if (!i || (CURRENT->bh && !SUBSECTOR(i)))
|
||||
end_request(1);
|
||||
if (i > 0) {
|
||||
SET_INTR(&read_intr);
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
(void) inb_p(HD_STATUS);
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
do_hd_request();
|
||||
return;
|
||||
}
|
||||
|
||||
static void write_intr(void)
|
||||
{
|
||||
int i;
|
||||
int retries = 100000;
|
||||
|
||||
do {
|
||||
i = (unsigned) inb_p(HD_STATUS);
|
||||
if (i & BUSY_STAT)
|
||||
continue;
|
||||
if ((i & STAT_MASK) != STAT_OK)
|
||||
break;
|
||||
if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
|
||||
goto ok_to_write;
|
||||
} while (--retries > 0);
|
||||
sti();
|
||||
printk("HD: write_intr: status = 0x%02x\n",i);
|
||||
if (i & ERR_STAT) {
|
||||
hd_error = (unsigned) inb(HD_ERROR);
|
||||
printk("HD: write_intr: error = 0x%02x\n",hd_error);
|
||||
}
|
||||
bad_rw_intr();
|
||||
cli();
|
||||
do_hd_request();
|
||||
return;
|
||||
ok_to_write:
|
||||
CURRENT->sector++;
|
||||
i = --CURRENT->nr_sectors;
|
||||
--CURRENT->current_nr_sectors;
|
||||
CURRENT->buffer += 512;
|
||||
if (!i || (CURRENT->bh && !SUBSECTOR(i)))
|
||||
end_request(1);
|
||||
if (i > 0) {
|
||||
SET_INTR(&write_intr);
|
||||
outsw(HD_DATA,CURRENT->buffer,256);
|
||||
sti();
|
||||
} else {
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
do_hd_request();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void recal_intr(void)
|
||||
{
|
||||
if (win_result())
|
||||
bad_rw_intr();
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is another of the error-routines I don't know what to do with. The
|
||||
* best idea seems to just set reset, and start all over again.
|
||||
*/
|
||||
static void hd_times_out(void)
|
||||
{
|
||||
DEVICE_INTR = NULL;
|
||||
sti();
|
||||
reset = 1;
|
||||
if (!CURRENT)
|
||||
return;
|
||||
printk(KERN_DEBUG "HD timeout\n");
|
||||
cli();
|
||||
if (++CURRENT->errors >= MAX_ERRORS) {
|
||||
#ifdef DEBUG
|
||||
printk("hd : too many errors.\n");
|
||||
#endif
|
||||
end_request(0);
|
||||
}
|
||||
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* The driver has been modified to enable interrupts a bit more: in order to
|
||||
* do this we first (a) disable the timeout-interrupt and (b) clear the
|
||||
* device-interrupt. This way the interrupts won't mess with out code (the
|
||||
* worst that can happen is that an unexpected HD-interrupt comes in and
|
||||
* sets the "reset" variable and starts the timer)
|
||||
*/
|
||||
static void do_hd_request(void)
|
||||
{
|
||||
unsigned int block,dev;
|
||||
unsigned int sec,head,cyl,track;
|
||||
unsigned int nsect;
|
||||
|
||||
if (CURRENT && CURRENT->dev < 0) return;
|
||||
|
||||
if (DEVICE_INTR)
|
||||
return;
|
||||
repeat:
|
||||
timer_active &= ~(1<<HD_TIMER);
|
||||
sti();
|
||||
INIT_REQUEST;
|
||||
dev = MINOR(CURRENT->dev);
|
||||
block = CURRENT->sector;
|
||||
nsect = CURRENT->nr_sectors;
|
||||
if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
|
||||
#ifdef DEBUG
|
||||
printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
|
||||
block, hd[dev].nr_sects);
|
||||
#endif
|
||||
end_request(0);
|
||||
goto repeat;
|
||||
}
|
||||
block += hd[dev].start_sect;
|
||||
dev >>= 6;
|
||||
sec = block % hd_info[dev].sect + 1;
|
||||
track = block / hd_info[dev].sect;
|
||||
head = track % hd_info[dev].head;
|
||||
cyl = track / hd_info[dev].head;
|
||||
#ifdef DEBUG
|
||||
printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
|
||||
dev, cyl, head, sec, CURRENT->buffer);
|
||||
#endif
|
||||
cli();
|
||||
if (reset) {
|
||||
int i;
|
||||
|
||||
for (i=0; i < NR_HD; i++)
|
||||
recalibrate[i] = 1;
|
||||
reset_hd();
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
if (recalibrate[dev]) {
|
||||
recalibrate[dev] = 0;
|
||||
hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
if (CURRENT->cmd == WRITE) {
|
||||
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
if (wait_DRQ()) {
|
||||
printk("HD: do_hd_request: no DRQ\n");
|
||||
bad_rw_intr();
|
||||
goto repeat;
|
||||
}
|
||||
outsw(HD_DATA,CURRENT->buffer,256);
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
if (CURRENT->cmd == READ) {
|
||||
hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
panic("unknown hd-command");
|
||||
}
|
||||
|
||||
static int hd_ioctl(struct inode * inode, struct file * file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct hd_geometry *loc = (struct hd_geometry *) arg;
|
||||
int dev, err;
|
||||
|
||||
if (!inode)
|
||||
return -EINVAL;
|
||||
dev = MINOR(inode->i_rdev) >> 6;
|
||||
if (dev >= NR_HD)
|
||||
return -EINVAL;
|
||||
switch (cmd) {
|
||||
case HDIO_GETGEO:
|
||||
if (!loc) return -EINVAL;
|
||||
err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
|
||||
if (err)
|
||||
return err;
|
||||
put_fs_byte(hd_info[dev].head,
|
||||
(char *) &loc->heads);
|
||||
put_fs_byte(hd_info[dev].sect,
|
||||
(char *) &loc->sectors);
|
||||
put_fs_word(hd_info[dev].cyl,
|
||||
(short *) &loc->cylinders);
|
||||
put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
|
||||
(long *) &loc->start);
|
||||
return 0;
|
||||
case BLKGETSIZE: /* Return device size */
|
||||
if (!arg) return -EINVAL;
|
||||
err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
|
||||
if (err)
|
||||
return err;
|
||||
put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,
|
||||
(long *) arg);
|
||||
return 0;
|
||||
case BLKFLSBUF:
|
||||
if(!suser()) return -EACCES;
|
||||
if(!inode->i_rdev) return -EINVAL;
|
||||
fsync_dev(inode->i_rdev);
|
||||
invalidate_buffers(inode->i_rdev);
|
||||
return 0;
|
||||
|
||||
case BLKRRPART: /* Re-read partition tables */
|
||||
return revalidate_hddisk(inode->i_rdev, 1);
|
||||
RO_IOCTLS(inode->i_rdev,arg);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int hd_open(struct inode * inode, struct file * filp)
|
||||
{
|
||||
int target;
|
||||
target = DEVICE_NR(MINOR(inode->i_rdev));
|
||||
|
||||
while (busy[target])
|
||||
sleep_on(&busy_wait);
|
||||
access_count[target]++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Releasing a block device means we sync() it, so that it can safely
|
||||
* be forgotten about...
|
||||
*/
|
||||
static void hd_release(struct inode * inode, struct file * file)
|
||||
{
|
||||
int target;
|
||||
sync_dev(inode->i_rdev);
|
||||
|
||||
target = DEVICE_NR(MINOR(inode->i_rdev));
|
||||
access_count[target]--;
|
||||
|
||||
}
|
||||
|
||||
static void hd_geninit(void);
|
||||
|
||||
static struct gendisk hd_gendisk = {
|
||||
MAJOR_NR, /* Major number */
|
||||
"hd", /* Major name */
|
||||
6, /* Bits to shift to get real from partition */
|
||||
1 << 6, /* Number of partitions per real */
|
||||
MAX_HD, /* maximum number of real */
|
||||
hd_geninit, /* init function */
|
||||
hd, /* hd struct */
|
||||
hd_sizes, /* block sizes */
|
||||
0, /* number */
|
||||
(void *) hd_info, /* internal */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
static void hd_interrupt(int unused)
|
||||
{
|
||||
void (*handler)(void) = DEVICE_INTR;
|
||||
|
||||
DEVICE_INTR = NULL;
|
||||
timer_active &= ~(1<<HD_TIMER);
|
||||
if (!handler)
|
||||
handler = unexpected_hd_interrupt;
|
||||
handler();
|
||||
sti();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
|
||||
* means we run the IRQ-handler with interrupts disabled: this is bad for
|
||||
* interrupt latency, but anything else has led to problems on some
|
||||
* machines...
|
||||
*
|
||||
* We enable interrupts in some of the routines after making sure it's
|
||||
* safe.
|
||||
*/
|
||||
static struct sigaction hd_sigaction = {
|
||||
hd_interrupt,
|
||||
0,
|
||||
SA_INTERRUPT,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void hd_geninit(void)
|
||||
{
|
||||
int drive, i;
|
||||
extern struct drive_info drive_info;
|
||||
unsigned char *BIOS = (unsigned char *) &drive_info;
|
||||
int cmos_disks;
|
||||
|
||||
if (!NR_HD) {
|
||||
for (drive=0 ; drive<2 ; drive++) {
|
||||
hd_info[drive].cyl = *(unsigned short *) BIOS;
|
||||
hd_info[drive].head = *(2+BIOS);
|
||||
hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
|
||||
hd_info[drive].ctl = *(8+BIOS);
|
||||
hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
|
||||
hd_info[drive].sect = *(14+BIOS);
|
||||
BIOS += 16;
|
||||
}
|
||||
|
||||
/*
|
||||
We querry CMOS about hard disks : it could be that
|
||||
we have a SCSI/ESDI/etc controller that is BIOS
|
||||
compatable with ST-506, and thus showing up in our
|
||||
BIOS table, but not register compatable, and therefore
|
||||
not present in CMOS.
|
||||
|
||||
Furthurmore, we will assume that our ST-506 drives
|
||||
<if any> are the primary drives in the system, and
|
||||
the ones reflected as drive 1 or 2.
|
||||
|
||||
The first drive is stored in the high nibble of CMOS
|
||||
byte 0x12, the second in the low nibble. This will be
|
||||
either a 4 bit drive type or 0xf indicating use byte 0x19
|
||||
for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
|
||||
|
||||
Needless to say, a non-zero value means we have
|
||||
an AT controller hard disk for that drive.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
|
||||
if (cmos_disks & 0x0f)
|
||||
NR_HD = 2;
|
||||
else
|
||||
NR_HD = 1;
|
||||
}
|
||||
i = NR_HD;
|
||||
while (i-- > 0) {
|
||||
hd[i<<6].nr_sects = 0;
|
||||
if (hd_info[i].head > 16) {
|
||||
printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n");
|
||||
printk(" probably due to non-standard sector translation. Giving up.\n");
|
||||
printk(" (disk %d: cyl=%d, sect=%d, head=%d)\n", i,
|
||||
hd_info[i].cyl,
|
||||
hd_info[i].sect,
|
||||
hd_info[i].head);
|
||||
if (i+1 == NR_HD)
|
||||
NR_HD--;
|
||||
continue;
|
||||
}
|
||||
hd[i<<6].nr_sects = hd_info[i].head*
|
||||
hd_info[i].sect*hd_info[i].cyl;
|
||||
}
|
||||
if (NR_HD) {
|
||||
if (irqaction(HD_IRQ,&hd_sigaction)) {
|
||||
printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
|
||||
NR_HD = 0;
|
||||
}
|
||||
}
|
||||
hd_gendisk.nr_real = NR_HD;
|
||||
|
||||
for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
|
||||
blksize_size[MAJOR_NR] = hd_blocksizes;
|
||||
}
|
||||
|
||||
static struct file_operations hd_fops = {
|
||||
NULL, /* lseek - default */
|
||||
block_read, /* read - general block-dev read */
|
||||
block_write, /* write - general block-dev write */
|
||||
NULL, /* readdir - bad */
|
||||
NULL, /* select */
|
||||
hd_ioctl, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
hd_open, /* open */
|
||||
hd_release, /* release */
|
||||
block_fsync /* fsync */
|
||||
};
|
||||
|
||||
unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
|
||||
{
|
||||
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
|
||||
printk("Unable to get major %d for harddisk\n",MAJOR_NR);
|
||||
return mem_start;
|
||||
}
|
||||
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
|
||||
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
|
||||
hd_gendisk.next = gendisk_head;
|
||||
gendisk_head = &hd_gendisk;
|
||||
timer_table[HD_TIMER].fn = hd_times_out;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#define DEVICE_BUSY busy[target]
|
||||
#define USAGE access_count[target]
|
||||
#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
|
||||
/* We assume that the the bios parameters do not change, so the disk capacity
|
||||
will not change */
|
||||
#undef MAYBE_REINIT
|
||||
#define GENDISK_STRUCT hd_gendisk
|
||||
|
||||
/*
|
||||
* This routine is called to flush all partitions and partition tables
|
||||
* for a changed scsi disk, and then re-read the new partition table.
|
||||
* If we are revalidating a disk because of a media change, then we
|
||||
* enter with usage == 0. If we are using an ioctl, we automatically have
|
||||
* usage == 1 (we need an open channel to use an ioctl :-), so this
|
||||
* is our limit.
|
||||
*/
|
||||
static int revalidate_hddisk(int dev, int maxusage)
|
||||
{
|
||||
int target, major;
|
||||
struct gendisk * gdev;
|
||||
int max_p;
|
||||
int start;
|
||||
int i;
|
||||
|
||||
target = DEVICE_NR(MINOR(dev));
|
||||
gdev = &GENDISK_STRUCT;
|
||||
|
||||
cli();
|
||||
if (DEVICE_BUSY || USAGE > maxusage) {
|
||||
sti();
|
||||
return -EBUSY;
|
||||
};
|
||||
DEVICE_BUSY = 1;
|
||||
sti();
|
||||
|
||||
max_p = gdev->max_p;
|
||||
start = target << gdev->minor_shift;
|
||||
major = MAJOR_NR << 8;
|
||||
|
||||
for (i=max_p - 1; i >=0 ; i--) {
|
||||
sync_dev(major | start | i);
|
||||
invalidate_inodes(major | start | i);
|
||||
invalidate_buffers(major | start | i);
|
||||
gdev->part[start+i].start_sect = 0;
|
||||
gdev->part[start+i].nr_sects = 0;
|
||||
};
|
||||
|
||||
#ifdef MAYBE_REINIT
|
||||
MAYBE_REINIT;
|
||||
#endif
|
||||
|
||||
gdev->part[start].nr_sects = CAPACITY;
|
||||
resetup_one_dev(gdev, target);
|
||||
|
||||
DEVICE_BUSY = 0;
|
||||
wake_up(&busy_wait);
|
||||
return 0;
|
||||
}
|
||||
|
503
source/THIRDPARTY/linux-old/drivers/block/ll_rw_blk.c
Normal file
503
source/THIRDPARTY/linux-old/drivers/block/ll_rw_blk.c
Normal file
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* linux/kernel/blk_dev/ll_rw.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* This handles all read/write requests to block devices
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/locks.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "blk.h"
|
||||
|
||||
#ifdef CONFIG_SBPCD
|
||||
extern u_long sbpcd_init(u_long, u_long);
|
||||
#endif CONFIG_SBPCD
|
||||
|
||||
/*
|
||||
* The request-struct contains all necessary data
|
||||
* to load a nr of sectors into memory
|
||||
*/
|
||||
static struct request all_requests[NR_REQUEST];
|
||||
|
||||
/*
|
||||
* used to wait on when there are no free requests
|
||||
*/
|
||||
struct wait_queue * wait_for_request = NULL;
|
||||
|
||||
/* This specifies how many sectors to read ahead on the disk. */
|
||||
|
||||
int read_ahead[MAX_BLKDEV] = {0, };
|
||||
|
||||
/* blk_dev_struct is:
|
||||
* do_request-address
|
||||
* next-request
|
||||
*/
|
||||
struct blk_dev_struct blk_dev[MAX_BLKDEV] = {
|
||||
{ NULL, NULL }, /* no_dev */
|
||||
{ NULL, NULL }, /* dev mem */
|
||||
{ NULL, NULL }, /* dev fd */
|
||||
{ NULL, NULL }, /* dev hd */
|
||||
{ NULL, NULL }, /* dev ttyx */
|
||||
{ NULL, NULL }, /* dev tty */
|
||||
{ NULL, NULL }, /* dev lp */
|
||||
{ NULL, NULL }, /* dev pipes */
|
||||
{ NULL, NULL }, /* dev sd */
|
||||
{ NULL, NULL } /* dev st */
|
||||
};
|
||||
|
||||
/*
|
||||
* blk_size contains the size of all block-devices in units of 1024 byte
|
||||
* sectors:
|
||||
*
|
||||
* blk_size[MAJOR][MINOR]
|
||||
*
|
||||
* if (!blk_size[MAJOR]) then no minor size checking is done.
|
||||
*/
|
||||
int * blk_size[MAX_BLKDEV] = { NULL, NULL, };
|
||||
|
||||
/*
|
||||
* blksize_size contains the size of all block-devices:
|
||||
*
|
||||
* blksize_size[MAJOR][MINOR]
|
||||
*
|
||||
* if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
|
||||
*/
|
||||
int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
|
||||
|
||||
/*
|
||||
* look for a free request in the first N entries.
|
||||
* NOTE: interrupts must be disabled on the way in, and will still
|
||||
* be disabled on the way out.
|
||||
*/
|
||||
static inline struct request * get_request(int n, int dev)
|
||||
{
|
||||
static struct request *prev_found = NULL, *prev_limit = NULL;
|
||||
register struct request *req, *limit;
|
||||
|
||||
if (n <= 0)
|
||||
panic("get_request(%d): impossible!\n", n);
|
||||
|
||||
limit = all_requests + n;
|
||||
if (limit != prev_limit) {
|
||||
prev_limit = limit;
|
||||
prev_found = all_requests;
|
||||
}
|
||||
req = prev_found;
|
||||
for (;;) {
|
||||
req = ((req > all_requests) ? req : limit) - 1;
|
||||
if (req->dev < 0)
|
||||
break;
|
||||
if (req == prev_found)
|
||||
return NULL;
|
||||
}
|
||||
prev_found = req;
|
||||
req->dev = dev;
|
||||
return req;
|
||||
}
|
||||
|
||||
/*
|
||||
* wait until a free request in the first N entries is available.
|
||||
* NOTE: interrupts must be disabled on the way in, and will still
|
||||
* be disabled on the way out.
|
||||
*/
|
||||
static inline struct request * get_request_wait(int n, int dev)
|
||||
{
|
||||
register struct request *req;
|
||||
|
||||
while ((req = get_request(n, dev)) == NULL)
|
||||
sleep_on(&wait_for_request);
|
||||
return req;
|
||||
}
|
||||
|
||||
/* RO fail safe mechanism */
|
||||
|
||||
static long ro_bits[MAX_BLKDEV][8];
|
||||
|
||||
int is_read_only(int dev)
|
||||
{
|
||||
int minor,major;
|
||||
|
||||
major = MAJOR(dev);
|
||||
minor = MINOR(dev);
|
||||
if (major < 0 || major >= MAX_BLKDEV) return 0;
|
||||
return ro_bits[major][minor >> 5] & (1 << (minor & 31));
|
||||
}
|
||||
|
||||
void set_device_ro(int dev,int flag)
|
||||
{
|
||||
int minor,major;
|
||||
|
||||
major = MAJOR(dev);
|
||||
minor = MINOR(dev);
|
||||
if (major < 0 || major >= MAX_BLKDEV) return;
|
||||
if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
|
||||
else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
|
||||
}
|
||||
|
||||
/*
|
||||
* add-request adds a request to the linked list.
|
||||
* It disables interrupts so that it can muck with the
|
||||
* request-lists in peace.
|
||||
*/
|
||||
static void add_request(struct blk_dev_struct * dev, struct request * req)
|
||||
{
|
||||
struct request * tmp;
|
||||
|
||||
req->next = NULL;
|
||||
cli();
|
||||
if (req->bh)
|
||||
req->bh->b_dirt = 0;
|
||||
if (!(tmp = dev->current_request)) {
|
||||
dev->current_request = req;
|
||||
(dev->request_fn)();
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
for ( ; tmp->next ; tmp = tmp->next) {
|
||||
if ((IN_ORDER(tmp,req) ||
|
||||
!IN_ORDER(tmp,tmp->next)) &&
|
||||
IN_ORDER(req,tmp->next))
|
||||
break;
|
||||
}
|
||||
req->next = tmp->next;
|
||||
tmp->next = req;
|
||||
|
||||
/* for SCSI devices, call request_fn unconditionally */
|
||||
if (scsi_major(MAJOR(req->dev)))
|
||||
(dev->request_fn)();
|
||||
|
||||
sti();
|
||||
}
|
||||
|
||||
static void make_request(int major,int rw, struct buffer_head * bh)
|
||||
{
|
||||
unsigned int sector, count;
|
||||
struct request * req;
|
||||
int rw_ahead, max_req;
|
||||
|
||||
/* WRITEA/READA is special case - it is not really needed, so if the */
|
||||
/* buffer is locked, we just forget about it, else it's a normal read */
|
||||
rw_ahead = (rw == READA || rw == WRITEA);
|
||||
if (rw_ahead) {
|
||||
if (bh->b_lock)
|
||||
return;
|
||||
if (rw == READA)
|
||||
rw = READ;
|
||||
else
|
||||
rw = WRITE;
|
||||
}
|
||||
if (rw!=READ && rw!=WRITE) {
|
||||
printk("Bad block dev command, must be R/W/RA/WA\n");
|
||||
return;
|
||||
}
|
||||
count = bh->b_size >> 9;
|
||||
sector = bh->b_blocknr * count;
|
||||
if (blk_size[major])
|
||||
if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) {
|
||||
bh->b_dirt = bh->b_uptodate = 0;
|
||||
return;
|
||||
}
|
||||
lock_buffer(bh);
|
||||
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
|
||||
unlock_buffer(bh);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we don't allow the write-requests to fill up the queue completely:
|
||||
* we want some room for reads: they take precedence. The last third
|
||||
* of the requests are only for reads.
|
||||
*/
|
||||
max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3);
|
||||
|
||||
/* big loop: look for a free request. */
|
||||
|
||||
repeat:
|
||||
cli();
|
||||
|
||||
/* The scsi disk drivers completely remove the request from the queue when
|
||||
* they start processing an entry. For this reason it is safe to continue
|
||||
* to add links to the top entry for scsi devices.
|
||||
*/
|
||||
if ((major == HD_MAJOR
|
||||
|| major == SCSI_DISK_MAJOR
|
||||
|| major == SCSI_CDROM_MAJOR)
|
||||
&& (req = blk_dev[major].current_request))
|
||||
{
|
||||
if (major == HD_MAJOR)
|
||||
req = req->next;
|
||||
while (req) {
|
||||
if (req->dev == bh->b_dev &&
|
||||
!req->waiting &&
|
||||
req->cmd == rw &&
|
||||
req->sector + req->nr_sectors == sector &&
|
||||
req->nr_sectors < 254)
|
||||
{
|
||||
req->bhtail->b_reqnext = bh;
|
||||
req->bhtail = bh;
|
||||
req->nr_sectors += count;
|
||||
bh->b_dirt = 0;
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->dev == bh->b_dev &&
|
||||
!req->waiting &&
|
||||
req->cmd == rw &&
|
||||
req->sector - count == sector &&
|
||||
req->nr_sectors < 254)
|
||||
{
|
||||
req->nr_sectors += count;
|
||||
bh->b_reqnext = req->bh;
|
||||
req->buffer = bh->b_data;
|
||||
req->current_nr_sectors = count;
|
||||
req->sector = sector;
|
||||
bh->b_dirt = 0;
|
||||
req->bh = bh;
|
||||
sti();
|
||||
return;
|
||||
}
|
||||
|
||||
req = req->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* find an unused request. */
|
||||
req = get_request(max_req, bh->b_dev);
|
||||
|
||||
/* if no request available: if rw_ahead, forget it; otherwise try again. */
|
||||
if (! req) {
|
||||
if (rw_ahead) {
|
||||
sti();
|
||||
unlock_buffer(bh);
|
||||
return;
|
||||
}
|
||||
sleep_on(&wait_for_request);
|
||||
sti();
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
/* we found a request. */
|
||||
sti();
|
||||
|
||||
/* fill up the request-info, and add it to the queue */
|
||||
req->cmd = rw;
|
||||
req->errors = 0;
|
||||
req->sector = sector;
|
||||
req->nr_sectors = count;
|
||||
req->current_nr_sectors = count;
|
||||
req->buffer = bh->b_data;
|
||||
req->waiting = NULL;
|
||||
req->bh = bh;
|
||||
req->bhtail = bh;
|
||||
req->next = NULL;
|
||||
add_request(major+blk_dev,req);
|
||||
}
|
||||
|
||||
void ll_rw_page(int rw, int dev, int page, char * buffer)
|
||||
{
|
||||
struct request * req;
|
||||
unsigned int major = MAJOR(dev);
|
||||
|
||||
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
|
||||
printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
|
||||
return;
|
||||
}
|
||||
if (rw!=READ && rw!=WRITE)
|
||||
panic("Bad block dev command, must be R/W");
|
||||
if (rw == WRITE && is_read_only(dev)) {
|
||||
printk("Can't page to read-only device 0x%X\n",dev);
|
||||
return;
|
||||
}
|
||||
cli();
|
||||
req = get_request_wait(NR_REQUEST, dev);
|
||||
sti();
|
||||
/* fill up the request-info, and add it to the queue */
|
||||
req->cmd = rw;
|
||||
req->errors = 0;
|
||||
req->sector = page<<3;
|
||||
req->nr_sectors = 8;
|
||||
req->current_nr_sectors = 8;
|
||||
req->buffer = buffer;
|
||||
req->waiting = current;
|
||||
req->bh = NULL;
|
||||
req->next = NULL;
|
||||
current->state = TASK_SWAPPING;
|
||||
add_request(major+blk_dev,req);
|
||||
schedule();
|
||||
}
|
||||
|
||||
/* This function can be used to request a number of buffers from a block
|
||||
device. Currently the only restriction is that all buffers must belong to
|
||||
the same device */
|
||||
|
||||
void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
|
||||
{
|
||||
unsigned int major;
|
||||
struct request plug;
|
||||
int plugged;
|
||||
int correct_size;
|
||||
struct blk_dev_struct * dev;
|
||||
int i;
|
||||
|
||||
/* Make sure that the first block contains something reasonable */
|
||||
while (!*bh) {
|
||||
bh++;
|
||||
if (--nr <= 0)
|
||||
return;
|
||||
};
|
||||
|
||||
dev = NULL;
|
||||
if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
|
||||
dev = blk_dev + major;
|
||||
if (!dev || !dev->request_fn) {
|
||||
printk(
|
||||
"ll_rw_block: Trying to read nonexistent block-device %04lX (%ld)\n",
|
||||
(unsigned long) bh[0]->b_dev, bh[0]->b_blocknr);
|
||||
goto sorry;
|
||||
}
|
||||
|
||||
/* Determine correct block size for this device. */
|
||||
correct_size = BLOCK_SIZE;
|
||||
if (blksize_size[major]) {
|
||||
i = blksize_size[major][MINOR(bh[0]->b_dev)];
|
||||
if (i)
|
||||
correct_size = i;
|
||||
}
|
||||
|
||||
/* Verify requested block sizees. */
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (bh[i] && bh[i]->b_size != correct_size) {
|
||||
printk(
|
||||
"ll_rw_block: only %d-char blocks implemented (%lu)\n",
|
||||
correct_size, bh[i]->b_size);
|
||||
goto sorry;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
|
||||
printk("Can't write to read-only device 0x%X\n",bh[0]->b_dev);
|
||||
goto sorry;
|
||||
}
|
||||
|
||||
/* If there are no pending requests for this device, then we insert
|
||||
a dummy request for that device. This will prevent the request
|
||||
from starting until we have shoved all of the blocks into the
|
||||
queue, and then we let it rip. */
|
||||
|
||||
plugged = 0;
|
||||
cli();
|
||||
if (!dev->current_request && nr > 1) {
|
||||
dev->current_request = &plug;
|
||||
plug.dev = -1;
|
||||
plug.next = NULL;
|
||||
plugged = 1;
|
||||
}
|
||||
sti();
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (bh[i]) {
|
||||
bh[i]->b_req = 1;
|
||||
make_request(major, rw, bh[i]);
|
||||
if (rw == READ || rw == READA)
|
||||
kstat.pgpgin++;
|
||||
else
|
||||
kstat.pgpgout++;
|
||||
}
|
||||
}
|
||||
if (plugged) {
|
||||
cli();
|
||||
dev->current_request = plug.next;
|
||||
(dev->request_fn)();
|
||||
sti();
|
||||
}
|
||||
return;
|
||||
|
||||
sorry:
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (bh[i])
|
||||
bh[i]->b_dirt = bh[i]->b_uptodate = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
|
||||
{
|
||||
int i;
|
||||
int buffersize;
|
||||
struct request * req;
|
||||
unsigned int major = MAJOR(dev);
|
||||
|
||||
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
|
||||
printk("ll_rw_swap_file: trying to swap nonexistent block-device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rw!=READ && rw!=WRITE) {
|
||||
printk("ll_rw_swap: bad block dev command, must be R/W");
|
||||
return;
|
||||
}
|
||||
if (rw == WRITE && is_read_only(dev)) {
|
||||
printk("Can't swap to read-only device 0x%X\n",dev);
|
||||
return;
|
||||
}
|
||||
|
||||
buffersize = PAGE_SIZE / nb;
|
||||
|
||||
for (i=0; i<nb; i++, buf += buffersize)
|
||||
{
|
||||
cli();
|
||||
req = get_request_wait(NR_REQUEST, dev);
|
||||
sti();
|
||||
req->cmd = rw;
|
||||
req->errors = 0;
|
||||
req->sector = (b[i] * buffersize) >> 9;
|
||||
req->nr_sectors = buffersize >> 9;
|
||||
req->current_nr_sectors = buffersize >> 9;
|
||||
req->buffer = buf;
|
||||
req->waiting = current;
|
||||
req->bh = NULL;
|
||||
req->next = NULL;
|
||||
current->state = TASK_UNINTERRUPTIBLE;
|
||||
add_request(major+blk_dev,req);
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
long blk_dev_init(long mem_start, long mem_end)
|
||||
{
|
||||
struct request * req;
|
||||
|
||||
req = all_requests + NR_REQUEST;
|
||||
while (--req >= all_requests) {
|
||||
req->dev = -1;
|
||||
req->next = NULL;
|
||||
}
|
||||
memset(ro_bits,0,sizeof(ro_bits));
|
||||
#ifdef CONFIG_BLK_DEV_HD
|
||||
mem_start = hd_init(mem_start,mem_end);
|
||||
#endif
|
||||
#ifdef CONFIG_BLK_DEV_XD
|
||||
mem_start = xd_init(mem_start,mem_end);
|
||||
#endif
|
||||
#ifdef CONFIG_CDU31A
|
||||
mem_start = cdu31a_init(mem_start,mem_end);
|
||||
#endif
|
||||
#ifdef CONFIG_MCD
|
||||
mem_start = mcd_init(mem_start,mem_end);
|
||||
#endif
|
||||
#ifdef CONFIG_SBPCD
|
||||
mem_start = sbpcd_init(mem_start, mem_end);
|
||||
#endif CONFIG_SBPCD
|
||||
if (ramdisk_size)
|
||||
mem_start += rd_init(mem_start, ramdisk_size*1024);
|
||||
return mem_start;
|
||||
}
|
1224
source/THIRDPARTY/linux-old/drivers/block/mcd.c
Normal file
1224
source/THIRDPARTY/linux-old/drivers/block/mcd.c
Normal file
File diff suppressed because it is too large
Load diff
178
source/THIRDPARTY/linux-old/drivers/block/ramdisk.c
Normal file
178
source/THIRDPARTY/linux-old/drivers/block/ramdisk.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* linux/kernel/blk_drv/ramdisk.c
|
||||
*
|
||||
* Written by Theodore Ts'o, 12/2/91
|
||||
*
|
||||
* Modifications by Fred N. van Kempen to allow for bootable root
|
||||
* disks (which are used in LINUX/Pro). Also some cleanups. 03/03/93
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/minix_fs.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define MAJOR_NR MEM_MAJOR
|
||||
#include "blk.h"
|
||||
|
||||
#define RAMDISK_MINOR 1
|
||||
|
||||
|
||||
char *rd_start;
|
||||
int rd_length = 0;
|
||||
static int rd_blocksizes[2] = {0, 0};
|
||||
|
||||
static void do_rd_request(void)
|
||||
{
|
||||
int len;
|
||||
char *addr;
|
||||
|
||||
repeat:
|
||||
INIT_REQUEST;
|
||||
addr = rd_start + (CURRENT->sector << 9);
|
||||
len = CURRENT->current_nr_sectors << 9;
|
||||
|
||||
if ((MINOR(CURRENT->dev) != RAMDISK_MINOR) ||
|
||||
(addr+len > rd_start+rd_length)) {
|
||||
end_request(0);
|
||||
goto repeat;
|
||||
}
|
||||
if (CURRENT-> cmd == WRITE) {
|
||||
(void ) memcpy(addr,
|
||||
CURRENT->buffer,
|
||||
len);
|
||||
} else if (CURRENT->cmd == READ) {
|
||||
(void) memcpy(CURRENT->buffer,
|
||||
addr,
|
||||
len);
|
||||
} else
|
||||
panic("RAMDISK: unknown RAM disk command !\n");
|
||||
end_request(1);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
static struct file_operations rd_fops = {
|
||||
NULL, /* lseek - default */
|
||||
block_read, /* read - general block-dev read */
|
||||
block_write, /* write - general block-dev write */
|
||||
NULL, /* readdir - bad */
|
||||
NULL, /* select */
|
||||
NULL, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
NULL, /* no special open code */
|
||||
NULL, /* no special release code */
|
||||
block_fsync /* fsync */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns amount of memory which needs to be reserved.
|
||||
*/
|
||||
long rd_init(long mem_start, int length)
|
||||
{
|
||||
int i;
|
||||
char *cp;
|
||||
|
||||
if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) {
|
||||
printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR);
|
||||
return 0;
|
||||
}
|
||||
blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST;
|
||||
rd_start = (char *) mem_start;
|
||||
rd_length = length;
|
||||
cp = rd_start;
|
||||
for (i=0; i < length; i++)
|
||||
*cp++ = '\0';
|
||||
|
||||
for(i=0;i<2;i++) rd_blocksizes[i] = 1024;
|
||||
blksize_size[MAJOR_NR] = rd_blocksizes;
|
||||
|
||||
return(length);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the root device is the RAM disk, try to load it.
|
||||
* In order to do this, the root device is originally set to the
|
||||
* floppy, and we later change it to be RAM disk.
|
||||
*/
|
||||
void rd_load(void)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
struct minix_super_block s;
|
||||
int block, tries;
|
||||
int i = 1;
|
||||
int nblocks;
|
||||
char *cp;
|
||||
|
||||
/* If no RAM disk specified, give up early. */
|
||||
if (!rd_length) return;
|
||||
printk("RAMDISK: %d bytes, starting at 0x%x\n",
|
||||
rd_length, (int) rd_start);
|
||||
|
||||
/* If we are doing a diskette boot, we might have to pre-load it. */
|
||||
if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
|
||||
|
||||
/*
|
||||
* Check for a super block on the diskette.
|
||||
* The old-style boot/root diskettes had their RAM image
|
||||
* starting at block 512 of the boot diskette. LINUX/Pro
|
||||
* uses the enire diskette as a file system, so in that
|
||||
* case, we have to look at block 0. Be intelligent about
|
||||
* this, and check both... - FvK
|
||||
*/
|
||||
for (tries = 0; tries < 1000; tries += 512) {
|
||||
block = tries;
|
||||
bh = breada(ROOT_DEV,block+1,block,block+2,-1);
|
||||
if (!bh) {
|
||||
printk("RAMDISK: I/O error while looking for super block!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is silly- why do we require it to be a MINIX FS? */
|
||||
*((struct minix_super_block *) &s) =
|
||||
*((struct minix_super_block *) bh->b_data);
|
||||
brelse(bh);
|
||||
nblocks = s.s_nzones << s.s_log_zone_size;
|
||||
if (s.s_magic != MINIX_SUPER_MAGIC &&
|
||||
s.s_magic != MINIX_SUPER_MAGIC2) {
|
||||
printk("RAMDISK: trying old-style RAM image.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) {
|
||||
printk("RAMDISK: image too big! (%d/%d blocks)\n",
|
||||
nblocks, rd_length >> BLOCK_SIZE_BITS);
|
||||
return;
|
||||
}
|
||||
printk("RAMDISK: Loading %d blocks into RAM disk", nblocks);
|
||||
|
||||
/* We found an image file system. Load it into core! */
|
||||
cp = rd_start;
|
||||
while (nblocks) {
|
||||
if (nblocks > 2)
|
||||
bh = breada(ROOT_DEV, block, block+1, block+2, -1);
|
||||
else
|
||||
bh = bread(ROOT_DEV, block, BLOCK_SIZE);
|
||||
if (!bh) {
|
||||
printk("RAMDISK: I/O error on block %d, aborting!\n",
|
||||
block);
|
||||
return;
|
||||
}
|
||||
(void) memcpy(cp, bh->b_data, BLOCK_SIZE);
|
||||
brelse(bh);
|
||||
if (!(nblocks-- & 15)) printk(".");
|
||||
cp += BLOCK_SIZE;
|
||||
block++;
|
||||
i++;
|
||||
}
|
||||
printk("\ndone\n");
|
||||
|
||||
/* We loaded the file system image. Prepare for mounting it. */
|
||||
ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR);
|
||||
return;
|
||||
}
|
||||
}
|
2996
source/THIRDPARTY/linux-old/drivers/block/sbpcd.c
Normal file
2996
source/THIRDPARTY/linux-old/drivers/block/sbpcd.c
Normal file
File diff suppressed because it is too large
Load diff
638
source/THIRDPARTY/linux-old/drivers/block/xd.c
Normal file
638
source/THIRDPARTY/linux-old/drivers/block/xd.c
Normal file
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* This file contains the driver for an XT hard disk controller (at least the DTC 5150X) for Linux.
|
||||
*
|
||||
* Author: Pat Mackinlay, smackinla@cc.curtin.edu.au
|
||||
* Date: 29/09/92
|
||||
*
|
||||
* Revised: 01/01/93, ...
|
||||
*
|
||||
* Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
|
||||
* Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/xd.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#define MAJOR_NR XT_DISK_MAJOR
|
||||
#include "blk.h"
|
||||
|
||||
XD_INFO xd_info[XD_MAXDRIVES];
|
||||
|
||||
/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
|
||||
signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
|
||||
few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
|
||||
command. Run DEBUG, and then you can examine your BIOS signature with:
|
||||
|
||||
d xxxx:0000
|
||||
|
||||
where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
|
||||
be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
|
||||
in the table are, in order:
|
||||
|
||||
offset ; this is the offset (in bytes) from the start of your ROM where the signature starts
|
||||
signature ; this is the actual text of the signature
|
||||
xd_?_init_controller ; this is the controller init routine used by your controller
|
||||
xd_?_init_drive ; this is the drive init routine used by your controller
|
||||
|
||||
The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
|
||||
made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
|
||||
best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
|
||||
may work with your card. If none of these seem to work, try sending me some email and I'll see what I can do <grin>.
|
||||
|
||||
NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
|
||||
should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
|
||||
|
||||
static XD_SIGNATURE xd_sigs[] = {
|
||||
{ 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
|
||||
{ 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
|
||||
{ 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
|
||||
{ 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
|
||||
{ 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
|
||||
{ 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
|
||||
{ 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
|
||||
};
|
||||
static u_char *xd_bases[] =
|
||||
{
|
||||
(u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xCC000,
|
||||
(u_char *) 0xCE000,(u_char *) 0xD0000,(u_char *) 0xD8000,
|
||||
(u_char *) 0xE0000
|
||||
};
|
||||
|
||||
static struct hd_struct xd[XD_MAXDRIVES << 6];
|
||||
static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 };
|
||||
static int xd_blocksizes[XD_MAXDRIVES << 6];
|
||||
static struct gendisk xd_gendisk = { MAJOR_NR,"xd",6,1 << 6,XD_MAXDRIVES,xd_geninit,xd,xd_sizes,0,(void *) xd_info,NULL };
|
||||
static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,xd_ioctl,NULL,xd_open,xd_release,block_fsync };
|
||||
|
||||
static struct wait_queue *xd_wait_int = NULL,*xd_wait_open = NULL;
|
||||
static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
|
||||
static u_char xd_drives = 0,xd_irq = 0,xd_dma = 0,xd_maxsectors,xd_override = 0,xd_type = 0;
|
||||
static u_short xd_iobase = 0;
|
||||
|
||||
/* xd_init: grab the IRQ and DMA channel and initialise the drives */
|
||||
u_long xd_init (u_long mem_start,u_long mem_end)
|
||||
{
|
||||
u_char i,controller,*address;
|
||||
|
||||
if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
|
||||
printk("xd_init: unable to get major number %d\n",MAJOR_NR);
|
||||
return (mem_start);
|
||||
}
|
||||
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
|
||||
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
|
||||
xd_gendisk.next = gendisk_head;
|
||||
gendisk_head = &xd_gendisk;
|
||||
|
||||
if (xd_detect(&controller,&address)) {
|
||||
|
||||
printk("xd_init: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
|
||||
if (controller)
|
||||
xd_sigs[controller].init_controller(address);
|
||||
xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
|
||||
|
||||
printk("xd_init: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
|
||||
for (i = 0; i < xd_drives; i++)
|
||||
printk("xd_init: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors);
|
||||
|
||||
if (!request_irq(xd_irq,xd_interrupt_handler)) {
|
||||
if (request_dma(xd_dma)) {
|
||||
printk("xd_init: unable to get DMA%d\n",xd_dma);
|
||||
free_irq(xd_irq);
|
||||
}
|
||||
}
|
||||
else
|
||||
printk("xd_init: unable to get IRQ%d\n",xd_irq);
|
||||
}
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
|
||||
static u_char xd_detect (u_char *controller,u_char **address)
|
||||
{
|
||||
u_char i,j,found = 0;
|
||||
|
||||
if (xd_override)
|
||||
{
|
||||
*controller = xd_type;
|
||||
*address = NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
|
||||
for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
|
||||
if (!memcmp(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
|
||||
*controller = j;
|
||||
*address = xd_bases[i];
|
||||
found++;
|
||||
}
|
||||
return (found);
|
||||
}
|
||||
|
||||
/* xd_geninit: set up the "raw" device entries in the table */
|
||||
static void xd_geninit (void)
|
||||
{
|
||||
u_char i;
|
||||
|
||||
for (i = 0; i < xd_drives; i++) {
|
||||
xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
|
||||
xd_valid[i] = 1;
|
||||
}
|
||||
|
||||
xd_gendisk.nr_real = xd_drives;
|
||||
|
||||
for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
|
||||
blksize_size[MAJOR_NR] = xd_blocksizes;
|
||||
}
|
||||
|
||||
/* xd_open: open a device */
|
||||
static int xd_open (struct inode *inode,struct file *file)
|
||||
{
|
||||
int dev = DEVICE_NR(MINOR(inode->i_rdev));
|
||||
|
||||
if (dev < xd_drives) {
|
||||
while (!xd_valid[dev])
|
||||
sleep_on(&xd_wait_open);
|
||||
|
||||
xd_access[dev]++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
/* do_xd_request: handle an incoming request */
|
||||
static void do_xd_request (void)
|
||||
{
|
||||
u_int block,count,retry;
|
||||
int code;
|
||||
|
||||
sti();
|
||||
while (code = 0, CURRENT) {
|
||||
INIT_REQUEST; /* do some checking on the request structure */
|
||||
|
||||
if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) {
|
||||
block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect;
|
||||
count = CURRENT->nr_sectors;
|
||||
|
||||
switch (CURRENT->cmd) {
|
||||
case READ:
|
||||
case WRITE: for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
|
||||
code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
|
||||
break;
|
||||
default: printk("do_xd_request: unknown request\n"); break;
|
||||
}
|
||||
}
|
||||
end_request(code); /* wrap up, 0 = fail, 1 = success */
|
||||
}
|
||||
}
|
||||
|
||||
/* xd_ioctl: handle device ioctl's */
|
||||
static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
|
||||
{
|
||||
XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
|
||||
int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
|
||||
|
||||
if (inode && (dev < xd_drives))
|
||||
switch (cmd) {
|
||||
case HDIO_GETGEO: if (arg) {
|
||||
if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
|
||||
return (err);
|
||||
put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
|
||||
put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
|
||||
put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
|
||||
put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
|
||||
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case BLKGETSIZE: if (arg) {
|
||||
if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
|
||||
return (err);
|
||||
put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case BLKFLSBUF:
|
||||
if(!suser()) return -EACCES;
|
||||
if(!inode->i_rdev) return -EINVAL;
|
||||
fsync_dev(inode->i_rdev);
|
||||
invalidate_buffers(inode->i_rdev);
|
||||
return 0;
|
||||
|
||||
case BLKRRPART: return (xd_reread_partitions(inode->i_rdev));
|
||||
RO_IOCTLS(inode->i_rdev,arg);
|
||||
}
|
||||
return (-EINVAL);
|
||||
}
|
||||
|
||||
/* xd_release: release the device */
|
||||
static void xd_release (struct inode *inode, struct file *file)
|
||||
{
|
||||
int dev = DEVICE_NR(MINOR(inode->i_rdev));
|
||||
|
||||
if (dev < xd_drives) {
|
||||
sync_dev(dev);
|
||||
xd_access[dev]--;
|
||||
}
|
||||
}
|
||||
|
||||
/* xd_reread_partitions: rereads the partition table from a drive */
|
||||
static int xd_reread_partitions(int dev)
|
||||
{
|
||||
int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
|
||||
|
||||
cli(); xd_valid[target] = (xd_access[target] != 1); sti();
|
||||
if (xd_valid[target])
|
||||
return (-EBUSY);
|
||||
|
||||
for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
|
||||
sync_dev(MAJOR_NR << 8 | start | partition);
|
||||
invalidate_inodes(MAJOR_NR << 8 | start | partition);
|
||||
invalidate_buffers(MAJOR_NR << 8 | start | partition);
|
||||
xd_gendisk.part[start + partition].start_sect = 0;
|
||||
xd_gendisk.part[start + partition].nr_sects = 0;
|
||||
};
|
||||
|
||||
xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
|
||||
resetup_one_dev(&xd_gendisk,target);
|
||||
|
||||
xd_valid[target] = 1;
|
||||
wake_up(&xd_wait_open);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* xd_readwrite: handle a read/write request */
|
||||
static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count)
|
||||
{
|
||||
u_char cmdblk[6],sense[4];
|
||||
u_short track,cylinder;
|
||||
u_char head,sector,control,mode,temp;
|
||||
|
||||
#ifdef DEBUG_READWRITE
|
||||
printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
|
||||
#endif /* DEBUG_READWRITE */
|
||||
|
||||
control = xd_info[drive].control;
|
||||
while (count) {
|
||||
temp = count < xd_maxsectors ? count : xd_maxsectors;
|
||||
|
||||
track = block / xd_info[drive].sectors;
|
||||
head = track % xd_info[drive].heads;
|
||||
cylinder = track / xd_info[drive].heads;
|
||||
sector = block % xd_info[drive].sectors;
|
||||
|
||||
#ifdef DEBUG_READWRITE
|
||||
printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
|
||||
#endif /* DEBUG_READWRITE */
|
||||
|
||||
mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
|
||||
xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
|
||||
|
||||
switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) {
|
||||
case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); return (0);
|
||||
case 2: switch ((sense[0] & 0x30) >> 4) {
|
||||
case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
|
||||
case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
|
||||
case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
|
||||
case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
|
||||
}
|
||||
if (sense[0] & 0x80)
|
||||
printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
|
||||
else
|
||||
printk(" - no valid disk address\n");
|
||||
return (0);
|
||||
}
|
||||
count -= temp, buffer += temp * 0x200, block += temp;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
|
||||
static void xd_recalibrate (u_char drive)
|
||||
{
|
||||
u_char cmdblk[6];
|
||||
|
||||
xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
|
||||
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
|
||||
printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
|
||||
}
|
||||
|
||||
/* xd_interrupt_handler: interrupt service routine */
|
||||
static void xd_interrupt_handler (int unused)
|
||||
{
|
||||
if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
|
||||
#ifdef DEBUG_OTHER
|
||||
printk("xd_interrupt_handler: interrupt detected\n");
|
||||
#endif /* DEBUG_OTHER */
|
||||
outb(0,XD_CONTROL); /* acknowledge interrupt */
|
||||
wake_up(&xd_wait_int); /* and wake up sleeping processes */
|
||||
}
|
||||
else
|
||||
printk("xd_interrupt_handler: unexpected interrupt\n");
|
||||
}
|
||||
|
||||
/* xd_dma: set up the DMA controller for a data transfer */
|
||||
static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
|
||||
{
|
||||
if (buffer < ((u_char *) 0x1000000 - count)) { /* transfer to address < 16M? */
|
||||
if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
|
||||
#ifdef DEBUG_OTHER
|
||||
printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
|
||||
#endif /* DEBUG_OTHER */
|
||||
return (PIO_MODE);
|
||||
}
|
||||
disable_dma(xd_dma);
|
||||
clear_dma_ff(xd_dma);
|
||||
set_dma_mode(xd_dma,mode);
|
||||
set_dma_addr(xd_dma,(u_int) buffer);
|
||||
set_dma_count(xd_dma,count);
|
||||
|
||||
return (DMA_MODE); /* use DMA and INT */
|
||||
}
|
||||
#ifdef DEBUG_OTHER
|
||||
printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
|
||||
#endif /* DEBUG_OTHER */
|
||||
return (PIO_MODE);
|
||||
}
|
||||
|
||||
/* xd_build: put stuff into an array in a format suitable for the controller */
|
||||
static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
|
||||
{
|
||||
cmdblk[0] = command;
|
||||
cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
|
||||
cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
|
||||
cmdblk[3] = cylinder & 0xFF;
|
||||
cmdblk[4] = count;
|
||||
cmdblk[5] = control;
|
||||
|
||||
return (cmdblk);
|
||||
}
|
||||
|
||||
/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
|
||||
static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
|
||||
{
|
||||
u_long expiry = jiffies + timeout;
|
||||
|
||||
while (((inb(port) & mask) != flags) && (jiffies < expiry))
|
||||
;
|
||||
|
||||
return (jiffies >= expiry);
|
||||
}
|
||||
|
||||
/* xd_command: handle all data transfers necessary for a single command */
|
||||
static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
|
||||
{
|
||||
u_char cmdblk[6],csb,complete = 0;
|
||||
|
||||
#ifdef DEBUG_COMMAND
|
||||
printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
|
||||
#endif /* DEBUG_COMMAND */
|
||||
|
||||
outb(0,XD_SELECT);
|
||||
outb(mode,XD_CONTROL);
|
||||
|
||||
if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
|
||||
return (1);
|
||||
|
||||
while (!complete) {
|
||||
if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
|
||||
return (1);
|
||||
switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
|
||||
case 0: if (mode == DMA_MODE) {
|
||||
enable_dma(xd_dma);
|
||||
sleep_on(&xd_wait_int);
|
||||
disable_dma(xd_dma);
|
||||
}
|
||||
else
|
||||
outb(outdata ? *outdata++ : 0,XD_DATA);
|
||||
break;
|
||||
case STAT_INPUT: if (mode == DMA_MODE) {
|
||||
enable_dma(xd_dma);
|
||||
sleep_on(&xd_wait_int);
|
||||
disable_dma(xd_dma);
|
||||
}
|
||||
else
|
||||
if (indata)
|
||||
*indata++ = inb(XD_DATA);
|
||||
else
|
||||
inb(XD_DATA);
|
||||
break;
|
||||
case STAT_COMMAND: outb(command ? *command++ : 0,XD_DATA); break;
|
||||
case STAT_COMMAND
|
||||
| STAT_INPUT: complete = 1; break;
|
||||
}
|
||||
}
|
||||
csb = inb(XD_DATA);
|
||||
|
||||
if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
|
||||
return (1);
|
||||
|
||||
if (csb & CSB_ERROR) { /* read sense data if error */
|
||||
xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
|
||||
if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
|
||||
printk("xd_command: warning! sense command failed!\n");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_COMMAND
|
||||
printk("xd_command: completed with csb = 0x%X\n",csb);
|
||||
#endif /* DEBUG_COMMAND */
|
||||
|
||||
return (csb & CSB_ERROR);
|
||||
}
|
||||
|
||||
static u_char xd_initdrives (void (*init_drive)(u_char drive))
|
||||
{
|
||||
u_char cmdblk[6],i,count = 0;
|
||||
|
||||
for (i = 0; i < XD_MAXDRIVES; i++) {
|
||||
xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
|
||||
if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) {
|
||||
init_drive(count);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (count);
|
||||
}
|
||||
|
||||
static void xd_dtc_init_controller (u_char *address)
|
||||
{
|
||||
switch ((u_long) address) {
|
||||
case 0xC8000: xd_iobase = 0x320; break;
|
||||
case 0xCA000: xd_iobase = 0x324; break;
|
||||
default: printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
|
||||
xd_iobase = 0x320; break;
|
||||
}
|
||||
xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
|
||||
xd_dma = 3;
|
||||
xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
|
||||
|
||||
outb(0,XD_RESET); /* reset the controller */
|
||||
}
|
||||
|
||||
static void xd_dtc_init_drive (u_char drive)
|
||||
{
|
||||
u_char cmdblk[6],buf[64];
|
||||
|
||||
xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
|
||||
if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
|
||||
xd_info[drive].heads = buf[0x0A]; /* heads */
|
||||
xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
|
||||
xd_info[drive].sectors = 17; /* sectors */
|
||||
#if 0
|
||||
xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
|
||||
xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
|
||||
xd_info[drive].ecc = buf[0x0F]; /* ecc length */
|
||||
#endif /* 0 */
|
||||
xd_info[drive].control = 0; /* control byte */
|
||||
|
||||
xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
|
||||
xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
|
||||
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
|
||||
printk("xd_dtc_init_drive: error setting step rate for drive %d\n",drive);
|
||||
}
|
||||
else
|
||||
printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
|
||||
}
|
||||
|
||||
static void xd_wd_init_controller (u_char *address)
|
||||
{
|
||||
switch ((u_long) address) {
|
||||
case 0xC8000: xd_iobase = 0x320; break;
|
||||
case 0xCA000: xd_iobase = 0x324; break;
|
||||
case 0xCC000: xd_iobase = 0x328; break;
|
||||
case 0xCE000: xd_iobase = 0x32C; break;
|
||||
case 0xD0000: xd_iobase = 0x328; break;
|
||||
case 0xD8000: xd_iobase = 0x32C; break;
|
||||
default: printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
|
||||
xd_iobase = 0x320; break;
|
||||
}
|
||||
xd_irq = 5; /* don't know how to auto-detect this yet */
|
||||
xd_dma = 3;
|
||||
xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
|
||||
|
||||
/* outb(0,XD_RESET); */ /* reset the controller */
|
||||
}
|
||||
|
||||
static void xd_wd_init_drive (u_char drive)
|
||||
{
|
||||
u_char cmdblk[6],buf[0x200];
|
||||
|
||||
xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
|
||||
if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
|
||||
xd_info[drive].heads = buf[0x1AF]; /* heads */
|
||||
xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
|
||||
xd_info[drive].sectors = 17; /* sectors */
|
||||
#if 0
|
||||
xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
|
||||
xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
|
||||
xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
|
||||
#endif /* 0 */
|
||||
xd_info[drive].control = buf[0x1B5]; /* control byte */
|
||||
|
||||
xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
|
||||
}
|
||||
else
|
||||
printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
|
||||
}
|
||||
|
||||
static void xd_seagate_init_controller (u_char *address)
|
||||
{
|
||||
switch ((u_long) address) {
|
||||
case 0xC8000: xd_iobase = 0x320; break;
|
||||
case 0xD0000: xd_iobase = 0x324; break;
|
||||
case 0xD8000: xd_iobase = 0x328; break;
|
||||
case 0xE0000: xd_iobase = 0x32C; break;
|
||||
default: printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
|
||||
xd_iobase = 0x320; break;
|
||||
}
|
||||
xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
|
||||
xd_dma = 3;
|
||||
xd_maxsectors = 0x40;
|
||||
|
||||
outb(0,XD_RESET); /* reset the controller */
|
||||
}
|
||||
|
||||
static void xd_seagate_init_drive (u_char drive)
|
||||
{
|
||||
u_char cmdblk[6],buf[0x200];
|
||||
|
||||
xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
|
||||
if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
|
||||
xd_info[drive].heads = buf[0x04]; /* heads */
|
||||
xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
|
||||
xd_info[drive].sectors = buf[0x05]; /* sectors */
|
||||
xd_info[drive].control = 0; /* control byte */
|
||||
}
|
||||
else
|
||||
printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive);
|
||||
}
|
||||
|
||||
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
|
||||
etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
|
||||
static void xd_override_init_drive (u_char drive)
|
||||
{
|
||||
u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
|
||||
u_char cmdblk[6],i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
while (min[i] != max[i] - 1) {
|
||||
test[i] = (min[i] + max[i]) / 2;
|
||||
xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
|
||||
if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
|
||||
min[i] = test[i];
|
||||
else
|
||||
max[i] = test[i];
|
||||
}
|
||||
test[i] = min[i];
|
||||
}
|
||||
xd_info[drive].heads = (u_char) min[0] + 1;
|
||||
xd_info[drive].cylinders = (u_short) min[1] + 1;
|
||||
xd_info[drive].sectors = (u_char) min[2] + 1;
|
||||
xd_info[drive].control = 0;
|
||||
}
|
||||
|
||||
/* xd_setup: initialise from command line parameters */
|
||||
void xd_setup (char *command,int *integers)
|
||||
{
|
||||
xd_override = 1;
|
||||
|
||||
xd_type = integers[1];
|
||||
xd_irq = integers[2];
|
||||
xd_iobase = integers[3];
|
||||
xd_dma = integers[4];
|
||||
|
||||
xd_maxsectors = 0x01;
|
||||
}
|
||||
|
||||
/* xd_setparam: set the drive characteristics */
|
||||
static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
|
||||
{
|
||||
u_char cmdblk[14];
|
||||
|
||||
xd_build(cmdblk,command,drive,0,0,0,0,0);
|
||||
cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
|
||||
cmdblk[7] = (u_char) (cylinders & 0xFF);
|
||||
cmdblk[8] = heads & 0x1F;
|
||||
cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
|
||||
cmdblk[10] = (u_char) (rwrite & 0xFF);
|
||||
cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
|
||||
cmdblk[12] = (u_char) (wprecomp & 0xFF);
|
||||
cmdblk[13] = ecc;
|
||||
|
||||
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
|
||||
printk("xd_setparam: error setting characteristics for drive %d\n",drive);
|
||||
}
|
||||
|
87
source/THIRDPARTY/linux-old/drivers/char/Makefile
Normal file
87
source/THIRDPARTY/linux-old/drivers/char/Makefile
Normal file
|
@ -0,0 +1,87 @@
|
|||
#
|
||||
# Makefile for the kernel character device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
# Note 2! The CFLAGS definitions are now inherited from the
|
||||
# parent makes..
|
||||
#
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) -S $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
OBJS = tty_io.o console.o keyboard.o serial.o \
|
||||
tty_ioctl.o pty.o vt.o mem.o \
|
||||
defkeymap.o
|
||||
|
||||
SRCS = tty_io.c console.c keyboard.c serial.c \
|
||||
tty_ioctl.c pty.c vt.c mem.c \
|
||||
defkeymap.c
|
||||
|
||||
|
||||
ifdef CONFIG_ATIXL_BUSMOUSE
|
||||
M = y
|
||||
OBJS := $(OBJS) atixlmouse.o
|
||||
SRCS := $(SRCS) atixlmouse.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_BUSMOUSE
|
||||
M = y
|
||||
OBJS := $(OBJS) busmouse.o
|
||||
SRCS := $(SRCS) busmouse.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_PRINTER
|
||||
OBJS := $(OBJS) lp.o
|
||||
SRCS := $(SRCS) lp.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MS_BUSMOUSE
|
||||
M = y
|
||||
OBJS := $(OBJS) msbusmouse.o
|
||||
SRCS := $(SRCS) msbusmouse.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_82C710_MOUSE
|
||||
CONFIG_PSMOUSE = CONFIG_PSMOUSE
|
||||
endif
|
||||
|
||||
ifdef CONFIG_PSMOUSE
|
||||
M = y
|
||||
OBJS := $(OBJS) psaux.o
|
||||
SRCS := $(SRCS) psaux.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_TAPE_QIC02
|
||||
OBJS := $(OBJS) tpqic02.o
|
||||
SRCS := $(SRCS) tpqic02.c
|
||||
endif
|
||||
|
||||
ifdef M
|
||||
OBJS := $(OBJS) mouse.o
|
||||
SRCS := $(SRCS) mouse.c
|
||||
endif
|
||||
|
||||
all: char.a
|
||||
|
||||
char.a: $(OBJS)
|
||||
$(AR) rcs char.a $(OBJS)
|
||||
sync
|
||||
|
||||
dep:
|
||||
$(CPP) -M $(SRCS) > .depend
|
||||
|
||||
dummy:
|
||||
|
||||
#
|
||||
# include a dependency file if one exists
|
||||
#
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
include .depend
|
||||
endif
|
198
source/THIRDPARTY/linux-old/drivers/char/atixlmouse.c
Normal file
198
source/THIRDPARTY/linux-old/drivers/char/atixlmouse.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* ATI XL Bus Mouse Driver for Linux
|
||||
* by Bob Harris (rth@sparta.com)
|
||||
*
|
||||
* Uses VFS interface for linux 0.98 (01OCT92)
|
||||
*
|
||||
* Modified by Chris Colohan (colohan@eecg.toronto.edu)
|
||||
*
|
||||
* version 0.3
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */
|
||||
#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */
|
||||
|
||||
/* ATI XL Inport Busmouse Definitions */
|
||||
|
||||
#define ATIXL_MSE_DATA_PORT 0x23d
|
||||
#define ATIXL_MSE_SIGNATURE_PORT 0x23e
|
||||
#define ATIXL_MSE_CONTROL_PORT 0x23c
|
||||
|
||||
#define ATIXL_MSE_READ_BUTTONS 0x00
|
||||
#define ATIXL_MSE_READ_X 0x01
|
||||
#define ATIXL_MSE_READ_Y 0x02
|
||||
|
||||
/* Some nice ATI XL macros */
|
||||
|
||||
/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */
|
||||
#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
|
||||
outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
|
||||
|
||||
/* Select IR7, Enable updates (INT ENABLED) */
|
||||
#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
|
||||
outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
|
||||
|
||||
/* Select IR7 - Mode Register, NO INTERRUPTS */
|
||||
#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
|
||||
outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
|
||||
|
||||
/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */
|
||||
#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
|
||||
outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
|
||||
|
||||
/* Same general mouse structure */
|
||||
|
||||
static struct mouse_status {
|
||||
char buttons;
|
||||
char latch_buttons;
|
||||
int dx;
|
||||
int dy;
|
||||
int present;
|
||||
int ready;
|
||||
int active;
|
||||
struct wait_queue *wait;
|
||||
} mouse;
|
||||
|
||||
void mouse_interrupt(int unused)
|
||||
{
|
||||
char dx, dy, buttons;
|
||||
|
||||
ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */
|
||||
outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */
|
||||
dx = inb( ATIXL_MSE_DATA_PORT);
|
||||
outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */
|
||||
dy = inb( ATIXL_MSE_DATA_PORT);
|
||||
outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
|
||||
buttons = inb( ATIXL_MSE_DATA_PORT);
|
||||
if (dx != 0 || dy != 0 || buttons != mouse.latch_buttons) {
|
||||
mouse.latch_buttons |= buttons;
|
||||
mouse.dx += dx;
|
||||
mouse.dy += dy;
|
||||
mouse.ready = 1;
|
||||
wake_up_interruptible(&mouse.wait);
|
||||
}
|
||||
ATIXL_MSE_ENABLE_UPDATE();
|
||||
}
|
||||
|
||||
static void release_mouse(struct inode * inode, struct file * file)
|
||||
{
|
||||
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
|
||||
mouse.active = 0;
|
||||
mouse.ready = 0;
|
||||
free_irq(ATIXL_MOUSE_IRQ);
|
||||
}
|
||||
|
||||
|
||||
static int open_mouse(struct inode * inode, struct file * file)
|
||||
{
|
||||
if (!mouse.present)
|
||||
return -EINVAL;
|
||||
if (mouse.active)
|
||||
return -EBUSY;
|
||||
mouse.active = 1;
|
||||
mouse.ready = 0;
|
||||
mouse.dx = 0;
|
||||
mouse.dy = 0;
|
||||
mouse.buttons = mouse.latch_buttons = 0;
|
||||
if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt)) {
|
||||
mouse.active = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (count < 3)
|
||||
return -EINVAL;
|
||||
if (!mouse.ready)
|
||||
return -EAGAIN;
|
||||
ATIXL_MSE_DISABLE_UPDATE();
|
||||
/* Allowed interrupts to occur during data gathering - shouldn't hurt */
|
||||
put_fs_byte((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
|
||||
if (mouse.dx < -127)
|
||||
mouse.dx = -127;
|
||||
if (mouse.dx > 127)
|
||||
mouse.dx = 127;
|
||||
put_fs_byte((char)mouse.dx, buffer + 1);
|
||||
if (mouse.dy < -127)
|
||||
mouse.dy = -127;
|
||||
if (mouse.dy > 127)
|
||||
mouse.dy = 127;
|
||||
put_fs_byte((char)-mouse.dy, buffer + 2);
|
||||
for(i = 3; i < count; i++)
|
||||
put_fs_byte(0x00, buffer + i);
|
||||
mouse.dx = 0;
|
||||
mouse.dy = 0;
|
||||
mouse.latch_buttons = mouse.buttons;
|
||||
mouse.ready = 0;
|
||||
ATIXL_MSE_ENABLE_UPDATE();
|
||||
return i; /* i data bytes returned */
|
||||
}
|
||||
|
||||
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||||
{
|
||||
if (sel_type != SEL_IN)
|
||||
return 0;
|
||||
if (mouse.ready)
|
||||
return 1;
|
||||
select_wait(&mouse.wait,wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct file_operations atixl_busmouse_fops = {
|
||||
NULL, /* mouse_seek */
|
||||
read_mouse,
|
||||
write_mouse,
|
||||
NULL, /* mouse_readdir */
|
||||
mouse_select, /* mouse_select */
|
||||
NULL, /* mouse_ioctl */
|
||||
NULL, /* mouse_mmap */
|
||||
open_mouse,
|
||||
release_mouse,
|
||||
};
|
||||
|
||||
unsigned long atixl_busmouse_init(unsigned long kmem_start)
|
||||
{
|
||||
unsigned char a,b,c;
|
||||
|
||||
a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */
|
||||
b = inb( ATIXL_MSE_SIGNATURE_PORT );
|
||||
c = inb( ATIXL_MSE_SIGNATURE_PORT );
|
||||
if (( a != b ) && ( a == c ))
|
||||
printk("\nATI Inport ");
|
||||
else{
|
||||
mouse.present = 0;
|
||||
return kmem_start;
|
||||
}
|
||||
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
|
||||
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
|
||||
outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
|
||||
mouse.present = 1;
|
||||
mouse.active = 0;
|
||||
mouse.ready = 0;
|
||||
mouse.buttons = mouse.latch_buttons = 0;
|
||||
mouse.dx = mouse.dy = 0;
|
||||
mouse.wait = NULL;
|
||||
printk("Bus mouse detected and installed.\n");
|
||||
return kmem_start;
|
||||
}
|
239
source/THIRDPARTY/linux-old/drivers/char/busmouse.c
Normal file
239
source/THIRDPARTY/linux-old/drivers/char/busmouse.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Logitech Bus Mouse Driver for Linux
|
||||
* by James Banks
|
||||
*
|
||||
* Mods by Matthew Dillon
|
||||
* calls verify_area()
|
||||
* tracks better when X is busy or paging
|
||||
*
|
||||
* Heavily modified by David Giller
|
||||
* changed from queue- to counter- driven
|
||||
* hacked out a (probably incorrect) mouse_select
|
||||
*
|
||||
* Modified again by Nathan Laredo to interface with
|
||||
* 0.96c-pl1 IRQ handling changes (13JUL92)
|
||||
* didn't bother touching select code.
|
||||
*
|
||||
* Modified the select() code blindly to conform to the VFS
|
||||
* requirements. 92.07.14 - Linus. Somebody should test it out.
|
||||
*
|
||||
* Modified by Johan Myreen to make room for other mice (9AUG92)
|
||||
* removed assignment chr_fops[10] = &mouse_fops; see mouse.c
|
||||
* renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
|
||||
* renamed this file mouse.c => busmouse.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/busmouse.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
static struct mouse_status mouse;
|
||||
static int mouse_irq = MOUSE_IRQ;
|
||||
|
||||
void bmouse_setup(char *str, int *ints)
|
||||
{
|
||||
if (ints[0] > 0)
|
||||
mouse_irq=ints[1];
|
||||
}
|
||||
|
||||
static void mouse_interrupt(int unused)
|
||||
{
|
||||
char dx, dy;
|
||||
unsigned char buttons;
|
||||
|
||||
MSE_INT_OFF();
|
||||
outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
|
||||
dx = (inb(MSE_DATA_PORT) & 0xf);
|
||||
outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
|
||||
dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
|
||||
outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
|
||||
dy = (inb(MSE_DATA_PORT) & 0xf);
|
||||
outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
|
||||
buttons = inb(MSE_DATA_PORT);
|
||||
dy |= (buttons & 0xf) << 4;
|
||||
buttons = ((buttons >> 5) & 0x07);
|
||||
if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
|
||||
mouse.buttons = buttons;
|
||||
mouse.dx += dx;
|
||||
mouse.dy -= dy;
|
||||
mouse.ready = 1;
|
||||
wake_up_interruptible(&mouse.wait);
|
||||
|
||||
/*
|
||||
* keep dx/dy reasonable, but still able to track when X (or
|
||||
* whatever) must page or is busy (i.e. long waits between
|
||||
* reads)
|
||||
*/
|
||||
if (mouse.dx < -2048)
|
||||
mouse.dx = -2048;
|
||||
if (mouse.dx > 2048)
|
||||
mouse.dx = 2048;
|
||||
|
||||
if (mouse.dy < -2048)
|
||||
mouse.dy = -2048;
|
||||
if (mouse.dy > 2048)
|
||||
mouse.dy = 2048;
|
||||
}
|
||||
MSE_INT_ON();
|
||||
}
|
||||
|
||||
/*
|
||||
* close access to the mouse (can deal with multiple
|
||||
* opens if allowed in the future)
|
||||
*/
|
||||
|
||||
static void close_mouse(struct inode * inode, struct file * file)
|
||||
{
|
||||
if (--mouse.active == 0) {
|
||||
MSE_INT_OFF();
|
||||
free_irq(mouse_irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* open access to the mouse, currently only one open is
|
||||
* allowed.
|
||||
*/
|
||||
|
||||
static int open_mouse(struct inode * inode, struct file * file)
|
||||
{
|
||||
if (!mouse.present)
|
||||
return -EINVAL;
|
||||
if (mouse.active)
|
||||
return -EBUSY;
|
||||
mouse.ready = 0;
|
||||
mouse.dx = 0;
|
||||
mouse.dy = 0;
|
||||
mouse.buttons = 0x87;
|
||||
if (request_irq(mouse_irq, mouse_interrupt))
|
||||
return -EBUSY;
|
||||
mouse.active = 1;
|
||||
MSE_INT_ON();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* writes are disallowed
|
||||
*/
|
||||
|
||||
static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* read mouse data. Currently never blocks.
|
||||
*/
|
||||
|
||||
static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
int r;
|
||||
int dx;
|
||||
int dy;
|
||||
unsigned char buttons;
|
||||
|
||||
if (count < 3)
|
||||
return -EINVAL;
|
||||
if ((r = verify_area(VERIFY_WRITE, buffer, count)))
|
||||
return r;
|
||||
if (!mouse.ready)
|
||||
return -EAGAIN;
|
||||
|
||||
/*
|
||||
* Obtain the current mouse parameters and limit as appropriate for
|
||||
* the return data format. Interrupts are only disabled while
|
||||
* obtaining the parameters, NOT during the puts_fs_byte() calls,
|
||||
* so paging in put_fs_byte() does not effect mouse tracking.
|
||||
*/
|
||||
|
||||
MSE_INT_OFF();
|
||||
dx = mouse.dx;
|
||||
dy = mouse.dy;
|
||||
if (dx < -127)
|
||||
dx = -127;
|
||||
if (dx > 127)
|
||||
dx = 127;
|
||||
if (dy < -127)
|
||||
dy = -127;
|
||||
if (dy > 127)
|
||||
dy = 127;
|
||||
buttons = mouse.buttons;
|
||||
mouse.dx -= dx;
|
||||
mouse.dy -= dy;
|
||||
mouse.ready = 0;
|
||||
MSE_INT_ON();
|
||||
|
||||
put_fs_byte(buttons | 0x80, buffer);
|
||||
put_fs_byte((char)dx, buffer + 1);
|
||||
put_fs_byte((char)dy, buffer + 2);
|
||||
for (r = 3; r < count; r++)
|
||||
put_fs_byte(0x00, buffer + r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* select for mouse input, must disable the mouse interrupt while checking
|
||||
* mouse.ready/select_wait() to avoid race condition (though in reality
|
||||
* such a condition is not fatal to the proper operation of the mouse since
|
||||
* multiple interrupts generally occur).
|
||||
*/
|
||||
|
||||
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (sel_type == SEL_IN) {
|
||||
MSE_INT_OFF();
|
||||
if (mouse.ready) {
|
||||
r = 1;
|
||||
} else {
|
||||
select_wait(&mouse.wait, wait);
|
||||
}
|
||||
MSE_INT_ON();
|
||||
}
|
||||
return(r);
|
||||
}
|
||||
|
||||
struct file_operations bus_mouse_fops = {
|
||||
NULL, /* mouse_seek */
|
||||
read_mouse,
|
||||
write_mouse,
|
||||
NULL, /* mouse_readdir */
|
||||
mouse_select, /* mouse_select */
|
||||
NULL, /* mouse_ioctl */
|
||||
NULL, /* mouse_mmap */
|
||||
open_mouse,
|
||||
close_mouse,
|
||||
};
|
||||
|
||||
unsigned long bus_mouse_init(unsigned long kmem_start)
|
||||
{
|
||||
int i;
|
||||
|
||||
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
|
||||
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
|
||||
for (i = 0; i < 100000; i++)
|
||||
/* busy loop */;
|
||||
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
|
||||
mouse.present = 0;
|
||||
return kmem_start;
|
||||
}
|
||||
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
|
||||
MSE_INT_OFF();
|
||||
mouse.present = 1;
|
||||
mouse.active = 0;
|
||||
mouse.ready = 0;
|
||||
mouse.buttons = 0x87;
|
||||
mouse.dx = 0;
|
||||
mouse.dy = 0;
|
||||
mouse.wait = NULL;
|
||||
printk("Logitech Bus mouse detected and installed.\n");
|
||||
return kmem_start;
|
||||
}
|
1951
source/THIRDPARTY/linux-old/drivers/char/console.c
Normal file
1951
source/THIRDPARTY/linux-old/drivers/char/console.c
Normal file
File diff suppressed because it is too large
Load diff
399
source/THIRDPARTY/linux-old/drivers/char/defkeymap.c
Normal file
399
source/THIRDPARTY/linux-old/drivers/char/defkeymap.c
Normal file
|
@ -0,0 +1,399 @@
|
|||
/* Automatically generated by mktable */
|
||||
/* Do not edit this file! */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/keyboard.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
u_short key_map[NR_KEYMAPS][NR_KEYS] = {
|
||||
{
|
||||
0x0200, 0x001b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
|
||||
0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0x007f, 0x0009,
|
||||
0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
|
||||
0x0b6f, 0x0b70, 0x005b, 0x005d, 0x0201, 0x0702, 0x0b61, 0x0b73,
|
||||
0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x003b,
|
||||
0x0027, 0x0060, 0x0700, 0x005c, 0x0b7a, 0x0b78, 0x0b63, 0x0b76,
|
||||
0x0b62, 0x0b6e, 0x0b6d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c,
|
||||
0x0703, 0x0020, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
|
||||
0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0209, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003c, 0x010a,
|
||||
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
|
||||
0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009,
|
||||
0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49,
|
||||
0x0b4f, 0x0b50, 0x007b, 0x007d, 0x0201, 0x0702, 0x0b41, 0x0b53,
|
||||
0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x003a,
|
||||
0x0022, 0x007e, 0x0700, 0x007c, 0x0b5a, 0x0b58, 0x0b43, 0x0b56,
|
||||
0x0b42, 0x0b4e, 0x0b4d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c,
|
||||
0x0703, 0x0020, 0x0207, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
|
||||
0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0208, 0x0203, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003e, 0x010a,
|
||||
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200,
|
||||
0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200,
|
||||
0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
|
||||
0x0b6f, 0x0b70, 0x0200, 0x007e, 0x0201, 0x0702, 0x0b61, 0x0b73,
|
||||
0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x0b7a, 0x0b78, 0x0b63, 0x0b76,
|
||||
0x0b62, 0x0b6e, 0x0b6d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
|
||||
0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x007c, 0x0516,
|
||||
0x0517, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49,
|
||||
0x0b4f, 0x0b50, 0x0200, 0x0200, 0x0201, 0x0702, 0x0b41, 0x0b53,
|
||||
0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x0b5a, 0x0b58, 0x0b43, 0x0b56,
|
||||
0x0b42, 0x0b4e, 0x0b4d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e,
|
||||
0x001f, 0x007f, 0x0200, 0x0200, 0x001f, 0x0200, 0x0200, 0x0200,
|
||||
0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
|
||||
0x000f, 0x0010, 0x001b, 0x001d, 0x0201, 0x0702, 0x0001, 0x0013,
|
||||
0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
|
||||
0x0007, 0x0000, 0x0700, 0x001c, 0x001a, 0x0018, 0x0003, 0x0016,
|
||||
0x0002, 0x000e, 0x000d, 0x0200, 0x020e, 0x007f, 0x0700, 0x030c,
|
||||
0x0703, 0x0000, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
|
||||
0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0204, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x010a,
|
||||
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x001f, 0x0200, 0x0200, 0x0200,
|
||||
0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
|
||||
0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
|
||||
0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
|
||||
0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
|
||||
0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
|
||||
0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
|
||||
0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x020c, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
|
||||
0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
|
||||
0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
|
||||
0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x081b, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836,
|
||||
0x0837, 0x0838, 0x0839, 0x0830, 0x082d, 0x083d, 0x087f, 0x0809,
|
||||
0x0871, 0x0877, 0x0865, 0x0872, 0x0874, 0x0879, 0x0875, 0x0869,
|
||||
0x086f, 0x0870, 0x085b, 0x085d, 0x080d, 0x0702, 0x0861, 0x0873,
|
||||
0x0864, 0x0866, 0x0867, 0x0868, 0x086a, 0x086b, 0x086c, 0x083b,
|
||||
0x0827, 0x0860, 0x0700, 0x085c, 0x087a, 0x0878, 0x0863, 0x0876,
|
||||
0x0862, 0x086e, 0x086d, 0x082c, 0x082e, 0x082f, 0x0700, 0x030c,
|
||||
0x0703, 0x0820, 0x0207, 0x0500, 0x0501, 0x0502, 0x0503, 0x0504,
|
||||
0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x0208, 0x0209, 0x0907,
|
||||
0x0908, 0x0909, 0x030b, 0x0904, 0x0905, 0x0906, 0x030a, 0x0901,
|
||||
0x0902, 0x0903, 0x0900, 0x0310, 0x0206, 0x0200, 0x083c, 0x050a,
|
||||
0x050b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0851, 0x0857, 0x0845, 0x0852, 0x0854, 0x0859, 0x0855, 0x0849,
|
||||
0x084f, 0x0850, 0x0200, 0x0200, 0x0201, 0x0702, 0x0841, 0x0853,
|
||||
0x0844, 0x0846, 0x0847, 0x0848, 0x084a, 0x084b, 0x084c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x085a, 0x0858, 0x0843, 0x0856,
|
||||
0x0842, 0x084e, 0x084d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0871, 0x0877, 0x0865, 0x0872, 0x0874, 0x0879, 0x0875, 0x0869,
|
||||
0x086f, 0x0870, 0x0200, 0x0200, 0x0201, 0x0702, 0x0861, 0x0873,
|
||||
0x0864, 0x0866, 0x0867, 0x0868, 0x086a, 0x086b, 0x086c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x087a, 0x0878, 0x0863, 0x0876,
|
||||
0x0862, 0x086e, 0x086d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0851, 0x0857, 0x0845, 0x0852, 0x0854, 0x0859, 0x0855, 0x0849,
|
||||
0x084f, 0x0850, 0x0200, 0x0200, 0x0201, 0x0702, 0x0841, 0x0853,
|
||||
0x0844, 0x0846, 0x0847, 0x0848, 0x084a, 0x084b, 0x084c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x085a, 0x0858, 0x0843, 0x0856,
|
||||
0x0842, 0x084e, 0x084d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
|
||||
0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
|
||||
0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
|
||||
0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x020c, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
|
||||
0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
|
||||
0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
|
||||
0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
|
||||
0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
|
||||
0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
|
||||
0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
}, {
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
|
||||
0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
|
||||
0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
|
||||
0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
|
||||
0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
|
||||
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
|
||||
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
|
||||
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
|
||||
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
|
||||
0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
},
|
||||
};
|
||||
|
||||
char func_buf[FUNC_BUFSIZE] = {
|
||||
'\033', '[', '[', 'A', 0,
|
||||
'\033', '[', '[', 'B', 0,
|
||||
'\033', '[', '[', 'C', 0,
|
||||
'\033', '[', '[', 'D', 0,
|
||||
'\033', '[', '[', 'E', 0,
|
||||
'\033', '[', '1', '7', '~', 0,
|
||||
'\033', '[', '1', '8', '~', 0,
|
||||
'\033', '[', '1', '9', '~', 0,
|
||||
'\033', '[', '2', '0', '~', 0,
|
||||
'\033', '[', '2', '1', '~', 0,
|
||||
'\033', '[', '2', '3', '~', 0,
|
||||
'\033', '[', '2', '4', '~', 0,
|
||||
'\033', '[', '2', '5', '~', 0,
|
||||
'\033', '[', '2', '6', '~', 0,
|
||||
'\033', '[', '2', '8', '~', 0,
|
||||
'\033', '[', '2', '9', '~', 0,
|
||||
'\033', '[', '3', '1', '~', 0,
|
||||
'\033', '[', '3', '2', '~', 0,
|
||||
'\033', '[', '3', '3', '~', 0,
|
||||
'\033', '[', '3', '4', '~', 0,
|
||||
'\033', '[', '1', '~', 0,
|
||||
'\033', '[', '2', '~', 0,
|
||||
'\033', '[', '3', '~', 0,
|
||||
'\033', '[', '4', '~', 0,
|
||||
'\033', '[', '5', '~', 0,
|
||||
'\033', '[', '6', '~', 0,
|
||||
'\033', '[', 'M', 0,
|
||||
0,
|
||||
0,
|
||||
'\033', '[', 'P', 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
char *func_table[NR_FUNC] = {
|
||||
func_buf + 0,
|
||||
func_buf + 5,
|
||||
func_buf + 10,
|
||||
func_buf + 15,
|
||||
func_buf + 20,
|
||||
func_buf + 25,
|
||||
func_buf + 31,
|
||||
func_buf + 37,
|
||||
func_buf + 43,
|
||||
func_buf + 49,
|
||||
func_buf + 55,
|
||||
func_buf + 61,
|
||||
func_buf + 67,
|
||||
func_buf + 73,
|
||||
func_buf + 79,
|
||||
func_buf + 85,
|
||||
func_buf + 91,
|
||||
func_buf + 97,
|
||||
func_buf + 103,
|
||||
func_buf + 109,
|
||||
func_buf + 115,
|
||||
func_buf + 120,
|
||||
func_buf + 125,
|
||||
func_buf + 130,
|
||||
func_buf + 135,
|
||||
func_buf + 140,
|
||||
func_buf + 145,
|
||||
func_buf + 149,
|
||||
func_buf + 150,
|
||||
func_buf + 151,
|
||||
func_buf + 155,
|
||||
func_buf + 156,
|
||||
func_buf + 157,
|
||||
func_buf + 158,
|
||||
func_buf + 159,
|
||||
func_buf + 160,
|
||||
};
|
||||
|
||||
struct kbdiacr accent_table[MAX_DIACR] = {
|
||||
{'`', 'A', '\300'}, {'`', 'a', '\340'},
|
||||
{'\'', 'A', '\301'}, {'\'', 'a', '\341'},
|
||||
{'^', 'A', '\302'}, {'^', 'a', '\342'},
|
||||
{'~', 'A', '\303'}, {'~', 'a', '\343'},
|
||||
{'"', 'A', '\304'}, {'"', 'a', '\344'},
|
||||
{'O', 'A', '\305'}, {'o', 'a', '\345'},
|
||||
{'0', 'A', '\305'}, {'0', 'a', '\345'},
|
||||
{'A', 'A', '\305'}, {'a', 'a', '\345'},
|
||||
{'A', 'E', '\306'}, {'a', 'e', '\346'},
|
||||
{',', 'C', '\307'}, {',', 'c', '\347'},
|
||||
{'`', 'E', '\310'}, {'`', 'e', '\350'},
|
||||
{'\'', 'E', '\311'}, {'\'', 'e', '\351'},
|
||||
{'^', 'E', '\312'}, {'^', 'e', '\352'},
|
||||
{'"', 'E', '\313'}, {'"', 'e', '\353'},
|
||||
{'`', 'I', '\314'}, {'`', 'i', '\354'},
|
||||
{'\'', 'I', '\315'}, {'\'', 'i', '\355'},
|
||||
{'^', 'I', '\316'}, {'^', 'i', '\356'},
|
||||
{'"', 'I', '\317'}, {'"', 'i', '\357'},
|
||||
{'-', 'D', '\320'}, {'-', 'd', '\360'},
|
||||
{'~', 'N', '\321'}, {'~', 'n', '\361'},
|
||||
{'`', 'O', '\322'}, {'`', 'o', '\362'},
|
||||
{'\'', 'O', '\323'}, {'\'', 'o', '\363'},
|
||||
{'^', 'O', '\324'}, {'^', 'o', '\364'},
|
||||
{'~', 'O', '\325'}, {'~', 'o', '\365'},
|
||||
{'"', 'O', '\326'}, {'"', 'o', '\366'},
|
||||
{'/', 'O', '\330'}, {'/', 'o', '\370'},
|
||||
{'`', 'U', '\331'}, {'`', 'u', '\371'},
|
||||
{'\'', 'U', '\332'}, {'\'', 'u', '\372'},
|
||||
{'^', 'U', '\333'}, {'^', 'u', '\373'},
|
||||
{'"', 'U', '\334'}, {'"', 'u', '\374'},
|
||||
{'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
|
||||
{'T', 'H', '\336'}, {'t', 'h', '\376'},
|
||||
{'s', 's', '\337'}, {'"', 'y', '\377'},
|
||||
{'s', 'z', '\337'}, {'i', 'j', '\377'},
|
||||
};
|
||||
|
||||
unsigned int accent_table_size = 68;
|
321
source/THIRDPARTY/linux-old/drivers/char/defkeymap.map
Normal file
321
source/THIRDPARTY/linux-old/drivers/char/defkeymap.map
Normal file
|
@ -0,0 +1,321 @@
|
|||
keycode 0 =
|
||||
keycode 1 = Escape Escape
|
||||
alt keycode 1 = Meta_Escape
|
||||
keycode 2 = one exclam
|
||||
alt keycode 2 = Meta_one
|
||||
keycode 3 = two at at
|
||||
control keycode 3 = nul
|
||||
shift control keycode 3 = nul
|
||||
alt keycode 3 = Meta_two
|
||||
keycode 4 = three numbersign
|
||||
control keycode 4 = Escape
|
||||
alt keycode 4 = Meta_three
|
||||
keycode 5 = four dollar dollar
|
||||
control keycode 5 = Control_backslash
|
||||
alt keycode 5 = Meta_four
|
||||
keycode 6 = five percent
|
||||
control keycode 6 = Control_bracketright
|
||||
alt keycode 6 = Meta_five
|
||||
keycode 7 = six asciicircum
|
||||
control keycode 7 = Control_asciicircum
|
||||
alt keycode 7 = Meta_six
|
||||
keycode 8 = seven ampersand braceleft
|
||||
control keycode 8 = Control_underscore
|
||||
alt keycode 8 = Meta_seven
|
||||
keycode 9 = eight asterisk bracketleft
|
||||
control keycode 9 = Delete
|
||||
alt keycode 9 = Meta_eight
|
||||
keycode 10 = nine parenleft bracketright
|
||||
alt keycode 10 = Meta_nine
|
||||
keycode 11 = zero parenright braceright
|
||||
alt keycode 11 = Meta_zero
|
||||
keycode 12 = minus underscore backslash
|
||||
control keycode 12 = Control_underscore
|
||||
shift control keycode 12 = Control_underscore
|
||||
alt keycode 12 = Meta_minus
|
||||
keycode 13 = equal plus
|
||||
alt keycode 13 = Meta_equal
|
||||
keycode 14 = Delete Delete
|
||||
alt keycode 14 = Meta_Delete
|
||||
keycode 15 = Tab Tab
|
||||
alt keycode 15 = Meta_Tab
|
||||
keycode 16 = q
|
||||
keycode 17 = w
|
||||
keycode 18 = e
|
||||
keycode 19 = r
|
||||
keycode 20 = t
|
||||
keycode 21 = y
|
||||
keycode 22 = u
|
||||
keycode 23 = i
|
||||
keycode 24 = o
|
||||
keycode 25 = p
|
||||
keycode 26 = bracketleft braceleft
|
||||
control keycode 26 = Escape
|
||||
alt keycode 26 = Meta_bracketleft
|
||||
keycode 27 = bracketright braceright asciitilde
|
||||
control keycode 27 = Control_bracketright
|
||||
alt keycode 27 = Meta_bracketright
|
||||
keycode 28 = Return
|
||||
alt keycode 28 = Meta_Control_m
|
||||
keycode 29 = Control
|
||||
keycode 30 = a
|
||||
keycode 31 = s
|
||||
keycode 32 = d
|
||||
keycode 33 = f
|
||||
keycode 34 = g
|
||||
keycode 35 = h
|
||||
keycode 36 = j
|
||||
keycode 37 = k
|
||||
keycode 38 = l
|
||||
keycode 39 = semicolon colon
|
||||
alt keycode 39 = Meta_semicolon
|
||||
keycode 40 = apostrophe quotedbl
|
||||
control keycode 40 = Control_g
|
||||
alt keycode 40 = Meta_apostrophe
|
||||
keycode 41 = grave asciitilde
|
||||
control keycode 41 = nul
|
||||
alt keycode 41 = Meta_grave
|
||||
keycode 42 = Shift
|
||||
keycode 43 = backslash bar
|
||||
control keycode 43 = Control_backslash
|
||||
alt keycode 43 = Meta_backslash
|
||||
keycode 44 = z
|
||||
keycode 45 = x
|
||||
keycode 46 = c
|
||||
keycode 47 = v
|
||||
keycode 48 = b
|
||||
keycode 49 = n
|
||||
keycode 50 = m
|
||||
keycode 51 = comma less
|
||||
alt keycode 51 = Meta_comma
|
||||
keycode 52 = period greater
|
||||
control keycode 52 = Compose
|
||||
alt keycode 52 = Meta_period
|
||||
keycode 53 = slash question
|
||||
control keycode 53 = Delete
|
||||
alt keycode 53 = Meta_slash
|
||||
keycode 54 = Shift
|
||||
keycode 55 = KP_Multiply
|
||||
keycode 56 = Alt
|
||||
keycode 57 = space space
|
||||
control keycode 57 = nul
|
||||
alt keycode 57 = Meta_space
|
||||
keycode 58 = Caps_Lock
|
||||
keycode 59 = F1 F11 Console_13
|
||||
control keycode 59 = F1
|
||||
alt keycode 59 = Console_1
|
||||
keycode 60 = F2 F12 Console_14
|
||||
control keycode 60 = F2
|
||||
alt keycode 60 = Console_2
|
||||
keycode 61 = F3 F13 Console_15
|
||||
control keycode 61 = F3
|
||||
alt keycode 61 = Console_3
|
||||
keycode 62 = F4 F14 Console_16
|
||||
control keycode 62 = F4
|
||||
alt keycode 62 = Console_4
|
||||
keycode 63 = F5 F15 Console_17
|
||||
control keycode 63 = F5
|
||||
alt keycode 63 = Console_5
|
||||
keycode 64 = F6 F16 Console_18
|
||||
control keycode 64 = F6
|
||||
alt keycode 64 = Console_6
|
||||
keycode 65 = F7 F17 Console_19
|
||||
control keycode 65 = F7
|
||||
alt keycode 65 = Console_7
|
||||
keycode 66 = F8 F18 Console_20
|
||||
control keycode 66 = F8
|
||||
alt keycode 66 = Console_8
|
||||
keycode 67 = F9 F19 Console_21
|
||||
control keycode 67 = F9
|
||||
alt keycode 67 = Console_9
|
||||
keycode 68 = F10 F20 Console_22
|
||||
control keycode 68 = F10
|
||||
alt keycode 68 = Console_10
|
||||
keycode 69 = Num_Lock
|
||||
keycode 70 = Scroll_Lock Show_Memory Show_Registers
|
||||
control keycode 70 = Show_State
|
||||
alt keycode 70 = Scroll_Lock
|
||||
keycode 71 = KP_7
|
||||
alt keycode 71 = Ascii_7
|
||||
keycode 72 = KP_8
|
||||
alt keycode 72 = Ascii_8
|
||||
keycode 73 = KP_9
|
||||
alt keycode 73 = Ascii_9
|
||||
keycode 74 = KP_Subtract
|
||||
keycode 75 = KP_4
|
||||
alt keycode 75 = Ascii_4
|
||||
keycode 76 = KP_5
|
||||
alt keycode 76 = Ascii_5
|
||||
keycode 77 = KP_6
|
||||
alt keycode 77 = Ascii_6
|
||||
keycode 78 = KP_Add
|
||||
keycode 79 = KP_1
|
||||
alt keycode 79 = Ascii_1
|
||||
keycode 80 = KP_2
|
||||
alt keycode 80 = Ascii_2
|
||||
keycode 81 = KP_3
|
||||
alt keycode 81 = Ascii_3
|
||||
keycode 82 = KP_0
|
||||
alt keycode 82 = Ascii_0
|
||||
keycode 83 = KP_Period
|
||||
altgr control keycode 83 = Boot
|
||||
control alt keycode 83 = Boot
|
||||
keycode 84 = Last_Console
|
||||
keycode 85 =
|
||||
keycode 86 = less greater bar
|
||||
alt keycode 86 = Meta_less
|
||||
keycode 87 = F11 F11 Console_23
|
||||
control keycode 87 = F11
|
||||
alt keycode 87 = Console_11
|
||||
keycode 88 = F12 F12 Console_24
|
||||
control keycode 88 = F12
|
||||
alt keycode 88 = Console_12
|
||||
keycode 89 =
|
||||
keycode 90 =
|
||||
keycode 91 =
|
||||
keycode 92 =
|
||||
keycode 93 =
|
||||
keycode 94 =
|
||||
keycode 95 =
|
||||
keycode 96 = KP_Enter
|
||||
keycode 97 = Control
|
||||
keycode 98 = KP_Divide
|
||||
keycode 99 = Control_backslash
|
||||
control keycode 99 = Control_backslash
|
||||
alt keycode 99 = Control_backslash
|
||||
keycode 100 = AltGr
|
||||
keycode 101 = Break
|
||||
keycode 102 = Find
|
||||
keycode 103 = Up
|
||||
keycode 104 = Prior
|
||||
shift keycode 104 = Scroll_Backward
|
||||
keycode 105 = Left
|
||||
keycode 106 = Right
|
||||
keycode 107 = Select
|
||||
keycode 108 = Down
|
||||
keycode 109 = Next
|
||||
shift keycode 109 = Scroll_Forward
|
||||
keycode 110 = Insert
|
||||
keycode 111 = Remove
|
||||
altgr control keycode 111 = Boot
|
||||
control alt keycode 111 = Boot
|
||||
keycode 112 = Macro
|
||||
keycode 113 = F13
|
||||
keycode 114 = F14
|
||||
keycode 115 = Help
|
||||
keycode 116 = Do
|
||||
keycode 117 = F17
|
||||
keycode 118 = KP_MinPlus
|
||||
keycode 119 = Pause
|
||||
keycode 120 =
|
||||
keycode 121 =
|
||||
keycode 122 =
|
||||
keycode 123 =
|
||||
keycode 124 =
|
||||
keycode 125 =
|
||||
keycode 126 =
|
||||
keycode 127 =
|
||||
string F1 = "\033[[A"
|
||||
string F2 = "\033[[B"
|
||||
string F3 = "\033[[C"
|
||||
string F4 = "\033[[D"
|
||||
string F5 = "\033[[E"
|
||||
string F6 = "\033[17~"
|
||||
string F7 = "\033[18~"
|
||||
string F8 = "\033[19~"
|
||||
string F9 = "\033[20~"
|
||||
string F10 = "\033[21~"
|
||||
string F11 = "\033[23~"
|
||||
string F12 = "\033[24~"
|
||||
string F13 = "\033[25~"
|
||||
string F14 = "\033[26~"
|
||||
string F15 = "\033[28~"
|
||||
string F16 = "\033[29~"
|
||||
string F17 = "\033[31~"
|
||||
string F18 = "\033[32~"
|
||||
string F19 = "\033[33~"
|
||||
string F20 = "\033[34~"
|
||||
string Find = "\033[1~"
|
||||
string Insert = "\033[2~"
|
||||
string Remove = "\033[3~"
|
||||
string Select = "\033[4~"
|
||||
string Prior = "\033[5~"
|
||||
string Next = "\033[6~"
|
||||
string Help = ""
|
||||
string Do = ""
|
||||
string Macro = "\033[M"
|
||||
string Pause = "\033[P"
|
||||
string F21 = ""
|
||||
string F22 = ""
|
||||
string F23 = ""
|
||||
string F24 = ""
|
||||
string F25 = ""
|
||||
string F26 = ""
|
||||
compose '`' 'A' to 'À'
|
||||
compose '`' 'a' to 'à'
|
||||
compose '\'' 'A' to 'Á'
|
||||
compose '\'' 'a' to 'á'
|
||||
compose '^' 'A' to 'Â'
|
||||
compose '^' 'a' to 'â'
|
||||
compose '~' 'A' to 'Ã'
|
||||
compose '~' 'a' to 'ã'
|
||||
compose '"' 'A' to 'Ä'
|
||||
compose '"' 'a' to 'ä'
|
||||
compose 'O' 'A' to 'Å'
|
||||
compose 'o' 'a' to 'å'
|
||||
compose '0' 'A' to 'Å'
|
||||
compose '0' 'a' to 'å'
|
||||
compose 'A' 'A' to 'Å'
|
||||
compose 'a' 'a' to 'å'
|
||||
compose 'A' 'E' to 'Æ'
|
||||
compose 'a' 'e' to 'æ'
|
||||
compose ',' 'C' to 'Ç'
|
||||
compose ',' 'c' to 'ç'
|
||||
compose '`' 'E' to 'È'
|
||||
compose '`' 'e' to 'è'
|
||||
compose '\'' 'E' to 'É'
|
||||
compose '\'' 'e' to 'é'
|
||||
compose '^' 'E' to 'Ê'
|
||||
compose '^' 'e' to 'ê'
|
||||
compose '"' 'E' to 'Ë'
|
||||
compose '"' 'e' to 'ë'
|
||||
compose '`' 'I' to 'Ì'
|
||||
compose '`' 'i' to 'ì'
|
||||
compose '\'' 'I' to 'Í'
|
||||
compose '\'' 'i' to 'í'
|
||||
compose '^' 'I' to 'Î'
|
||||
compose '^' 'i' to 'î'
|
||||
compose '"' 'I' to 'Ï'
|
||||
compose '"' 'i' to 'ï'
|
||||
compose '-' 'D' to 'Ð'
|
||||
compose '-' 'd' to 'ð'
|
||||
compose '~' 'N' to 'Ñ'
|
||||
compose '~' 'n' to 'ñ'
|
||||
compose '`' 'O' to 'Ò'
|
||||
compose '`' 'o' to 'ò'
|
||||
compose '\'' 'O' to 'Ó'
|
||||
compose '\'' 'o' to 'ó'
|
||||
compose '^' 'O' to 'Ô'
|
||||
compose '^' 'o' to 'ô'
|
||||
compose '~' 'O' to 'Õ'
|
||||
compose '~' 'o' to 'õ'
|
||||
compose '"' 'O' to 'Ö'
|
||||
compose '"' 'o' to 'ö'
|
||||
compose '/' 'O' to 'Ø'
|
||||
compose '/' 'o' to 'ø'
|
||||
compose '`' 'U' to 'Ù'
|
||||
compose '`' 'u' to 'ù'
|
||||
compose '\'' 'U' to 'Ú'
|
||||
compose '\'' 'u' to 'ú'
|
||||
compose '^' 'U' to 'Û'
|
||||
compose '^' 'u' to 'û'
|
||||
compose '"' 'U' to 'Ü'
|
||||
compose '"' 'u' to 'ü'
|
||||
compose '\'' 'Y' to 'Ý'
|
||||
compose '\'' 'y' to 'ý'
|
||||
compose 'T' 'H' to 'Þ'
|
||||
compose 't' 'h' to 'þ'
|
||||
compose 's' 's' to 'ß'
|
||||
compose '"' 'y' to 'ÿ'
|
||||
compose 's' 'z' to 'ß'
|
||||
compose 'i' 'j' to 'ÿ'
|
8
source/THIRDPARTY/linux-old/drivers/char/diacr.h
Normal file
8
source/THIRDPARTY/linux-old/drivers/char/diacr.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef _DIACR_H
|
||||
#define _DIACR_H
|
||||
#include <linux/kd.h>
|
||||
|
||||
extern struct kbdiacr accent_table[];
|
||||
extern unsigned int accent_table_size;
|
||||
|
||||
#endif /* _DIACR_H */
|
107
source/THIRDPARTY/linux-old/drivers/char/kbd_kern.h
Normal file
107
source/THIRDPARTY/linux-old/drivers/char/kbd_kern.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
#ifndef _KBD_KERN_H
|
||||
#define _KBD_KERN_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#define set_leds() mark_bh(KEYBOARD_BH)
|
||||
|
||||
#include <linux/keyboard.h>
|
||||
|
||||
/*
|
||||
* kbd->xxx contains the VC-local things (flag settings etc..)
|
||||
*
|
||||
* Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
|
||||
* The code in KDGETLED / KDSETLED depends on the internal and
|
||||
* external order being the same.
|
||||
*
|
||||
* Note: lockstate is used as index in the array key_map.
|
||||
*/
|
||||
struct kbd_struct {
|
||||
unsigned char ledstate; /* 3 bits */
|
||||
unsigned char default_ledstate;
|
||||
#define VC_SCROLLOCK 0 /* scroll-lock mode */
|
||||
#define VC_NUMLOCK 1 /* numeric lock mode */
|
||||
#define VC_CAPSLOCK 2 /* capslock mode */
|
||||
|
||||
unsigned char lockstate; /* 4 bits - must be in 0..15 */
|
||||
#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */
|
||||
#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */
|
||||
#define VC_CTRLLOCK KG_CTRL /* control lock mode */
|
||||
#define VC_ALTLOCK KG_ALT /* alt lock mode */
|
||||
|
||||
unsigned char modeflags;
|
||||
#define VC_APPLIC 0 /* application key mode */
|
||||
#define VC_CKMODE 1 /* cursor key mode */
|
||||
#define VC_REPEAT 2 /* keyboard repeat */
|
||||
#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */
|
||||
#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */
|
||||
#define VC_PAUSE 5 /* pause key pressed - unused */
|
||||
#define VC_RAW 6 /* raw (scancode) mode */
|
||||
#define VC_MEDIUMRAW 7 /* medium raw (keycode) mode */
|
||||
};
|
||||
|
||||
extern struct kbd_struct kbd_table[];
|
||||
|
||||
|
||||
extern unsigned long kbd_init(unsigned long);
|
||||
|
||||
extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
return ((kbd->ledstate >> flag) & 1);
|
||||
}
|
||||
|
||||
extern inline int vc_kbd_lock(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
return ((kbd->lockstate >> flag) & 1);
|
||||
}
|
||||
|
||||
extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
return ((kbd->modeflags >> flag) & 1);
|
||||
}
|
||||
|
||||
extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->ledstate |= 1 << flag;
|
||||
}
|
||||
|
||||
extern inline void set_vc_kbd_lock(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->lockstate |= 1 << flag;
|
||||
}
|
||||
|
||||
extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->modeflags |= 1 << flag;
|
||||
}
|
||||
|
||||
extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->ledstate &= ~(1 << flag);
|
||||
}
|
||||
|
||||
extern inline void clr_vc_kbd_lock(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->lockstate &= ~(1 << flag);
|
||||
}
|
||||
|
||||
extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->modeflags &= ~(1 << flag);
|
||||
}
|
||||
|
||||
extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->ledstate ^= 1 << flag;
|
||||
}
|
||||
|
||||
extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->lockstate ^= 1 << flag;
|
||||
}
|
||||
|
||||
extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
kbd->modeflags ^= 1 << flag;
|
||||
}
|
||||
|
||||
#endif
|
870
source/THIRDPARTY/linux-old/drivers/char/keyboard.c
Normal file
870
source/THIRDPARTY/linux-old/drivers/char/keyboard.c
Normal file
|
@ -0,0 +1,870 @@
|
|||
/*
|
||||
* linux/kernel/chr_drv/keyboard.c
|
||||
*
|
||||
* Keyboard driver for Linux v0.99 using Latin-1.
|
||||
*
|
||||
* Written for linux by Johan Myreen as a translation from
|
||||
* the assembly version by Linus (with diacriticals added)
|
||||
*
|
||||
* Some additional features added by Christoph Niemann (ChN), March 1993
|
||||
* Loadable keymaps by Risto Kankkunen, May 1993
|
||||
* Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
|
||||
*/
|
||||
|
||||
#define KEYBOARD_IRQ 1
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/bitops.h>
|
||||
|
||||
#include "kbd_kern.h"
|
||||
#include "diacr.h"
|
||||
|
||||
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
#ifndef KBD_DEFMODE
|
||||
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
|
||||
#endif
|
||||
|
||||
#ifndef KBD_DEFLEDS
|
||||
#define KBD_DEFLEDS (1 << VC_NUMLOCK)
|
||||
#endif
|
||||
|
||||
#ifndef KBD_DEFLOCK
|
||||
#define KBD_DEFLOCK 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The default IO slowdown is doing 'inb()'s from 0x61, which should be
|
||||
* safe. But as that is the keyboard controller chip address, we do our
|
||||
* slowdowns here by doing short jumps: the keyboard controller should
|
||||
* be able to keep up
|
||||
*/
|
||||
#define REALLY_SLOW_IO
|
||||
#define SLOW_IO_BY_JUMPING
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
extern void do_keyboard_interrupt(void);
|
||||
extern void ctrl_alt_del(void);
|
||||
extern void change_console(unsigned int new_console);
|
||||
extern void scrollback(int);
|
||||
extern void scrollfront(int);
|
||||
|
||||
#define fake_keyboard_interrupt() \
|
||||
__asm__ __volatile__("int $0x21")
|
||||
|
||||
unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
|
||||
|
||||
/*
|
||||
* global state includes the following, and various static variables
|
||||
* in this module: prev_scancode, shift_state, diacr, npadch,
|
||||
* dead_key_next, last_console
|
||||
*/
|
||||
|
||||
/* shift state counters.. */
|
||||
static unsigned char k_down[NR_SHIFT] = {0, };
|
||||
/* keyboard key bitmap */
|
||||
static unsigned long key_down[8] = { 0, };
|
||||
|
||||
static int want_console = -1;
|
||||
static int last_console = 0; /* last used VC */
|
||||
static int dead_key_next = 0;
|
||||
static int shift_state = 0;
|
||||
static int npadch = -1; /* -1 or number assembled on pad */
|
||||
static unsigned char diacr = 0;
|
||||
static char rep = 0; /* flag telling character repeat */
|
||||
struct kbd_struct kbd_table[NR_CONSOLES];
|
||||
static struct kbd_struct * kbd = kbd_table;
|
||||
static struct tty_struct * tty = NULL;
|
||||
|
||||
/* used only by send_data - set by keyboard_interrupt */
|
||||
static volatile unsigned char acknowledge = 0;
|
||||
static volatile unsigned char resend = 0;
|
||||
|
||||
typedef void (*k_hand)(unsigned char value, char up_flag);
|
||||
typedef void (k_handfn)(unsigned char value, char up_flag);
|
||||
|
||||
static k_handfn
|
||||
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
|
||||
do_meta, do_ascii, do_lock, do_lowercase;
|
||||
|
||||
static k_hand key_handler[] = {
|
||||
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
|
||||
do_meta, do_ascii, do_lock, do_lowercase
|
||||
};
|
||||
|
||||
/* maximum values each key_handler can handle */
|
||||
const int max_vals[] = {
|
||||
255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT,
|
||||
255, 9, 3, 255
|
||||
};
|
||||
|
||||
const int NR_TYPES = SIZE(max_vals);
|
||||
|
||||
static void put_queue(int);
|
||||
static unsigned char handle_diacr(unsigned char);
|
||||
|
||||
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
|
||||
static struct pt_regs * pt_regs;
|
||||
|
||||
static int got_break = 0;
|
||||
|
||||
static inline void kb_wait(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<0x10000; i++)
|
||||
if ((inb_p(0x64) & 0x02) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
static inline void send_cmd(unsigned char c)
|
||||
{
|
||||
kb_wait();
|
||||
outb(c,0x64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translation of escaped scancodes to keysyms.
|
||||
* This should be user-settable.
|
||||
*/
|
||||
#define E0_BASE 96
|
||||
|
||||
#define E0_KPENTER (E0_BASE+0)
|
||||
#define E0_RCTRL (E0_BASE+1)
|
||||
#define E0_KPSLASH (E0_BASE+2)
|
||||
#define E0_PRSCR (E0_BASE+3)
|
||||
#define E0_RALT (E0_BASE+4)
|
||||
#define E0_BREAK (E0_BASE+5) /* (control-pause) */
|
||||
#define E0_HOME (E0_BASE+6)
|
||||
#define E0_UP (E0_BASE+7)
|
||||
#define E0_PGUP (E0_BASE+8)
|
||||
#define E0_LEFT (E0_BASE+9)
|
||||
#define E0_RIGHT (E0_BASE+10)
|
||||
#define E0_END (E0_BASE+11)
|
||||
#define E0_DOWN (E0_BASE+12)
|
||||
#define E0_PGDN (E0_BASE+13)
|
||||
#define E0_INS (E0_BASE+14)
|
||||
#define E0_DEL (E0_BASE+15)
|
||||
/* BTC */
|
||||
#define E0_MACRO (E0_BASE+16)
|
||||
/* LK450 */
|
||||
#define E0_F13 (E0_BASE+17)
|
||||
#define E0_F14 (E0_BASE+18)
|
||||
#define E0_HELP (E0_BASE+19)
|
||||
#define E0_DO (E0_BASE+20)
|
||||
#define E0_F17 (E0_BASE+21)
|
||||
#define E0_KPMINPLUS (E0_BASE+22)
|
||||
|
||||
#define E1_PAUSE (E0_BASE+23)
|
||||
|
||||
static unsigned char e0_keys[128] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
|
||||
0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
|
||||
0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
|
||||
E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
|
||||
E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
|
||||
E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
|
||||
E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x58-0x5f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
|
||||
0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
|
||||
};
|
||||
|
||||
static void keyboard_interrupt(int int_pt_regs)
|
||||
{
|
||||
unsigned char scancode;
|
||||
static unsigned int prev_scancode = 0; /* remember E0, E1 */
|
||||
char up_flag; /* 0 or 0200 */
|
||||
char raw_mode;
|
||||
|
||||
pt_regs = (struct pt_regs *) int_pt_regs;
|
||||
send_cmd(0xAD); /* disable keyboard */
|
||||
kb_wait();
|
||||
if ((inb_p(0x64) & kbd_read_mask) != 0x01)
|
||||
goto end_kbd_intr;
|
||||
scancode = inb(0x60);
|
||||
mark_bh(KEYBOARD_BH);
|
||||
if (scancode == 0xfa) {
|
||||
acknowledge = 1;
|
||||
goto end_kbd_intr;
|
||||
} else if (scancode == 0xfe) {
|
||||
resend = 1;
|
||||
goto end_kbd_intr;
|
||||
}
|
||||
tty = TTY_TABLE(0);
|
||||
kbd = kbd_table + fg_console;
|
||||
if ((raw_mode = vc_kbd_mode(kbd,VC_RAW))) {
|
||||
put_queue(scancode);
|
||||
/* we do not return yet, because we want to maintain
|
||||
the key_down array, so that we have the correct
|
||||
values when finishing RAW mode or when changing VT's */
|
||||
}
|
||||
if (scancode == 0xe0 || scancode == 0xe1) {
|
||||
prev_scancode = scancode;
|
||||
goto end_kbd_intr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert scancode to keysym, using prev_scancode.
|
||||
*/
|
||||
up_flag = (scancode & 0200);
|
||||
scancode &= 0x7f;
|
||||
|
||||
if (prev_scancode) {
|
||||
/*
|
||||
* usually it will be 0xe0, but a Pause key generates
|
||||
* e1 1d 45 e1 9d c5 when pressed, and nothing when released
|
||||
*/
|
||||
if (prev_scancode != 0xe0) {
|
||||
if (prev_scancode == 0xe1 && scancode == 0x1d) {
|
||||
prev_scancode = 0x100;
|
||||
goto end_kbd_intr;
|
||||
} else if (prev_scancode == 0x100 && scancode == 0x45) {
|
||||
scancode = E1_PAUSE;
|
||||
prev_scancode = 0;
|
||||
} else {
|
||||
printk("keyboard: unknown e1 escape sequence\n");
|
||||
prev_scancode = 0;
|
||||
goto end_kbd_intr;
|
||||
}
|
||||
} else {
|
||||
prev_scancode = 0;
|
||||
/*
|
||||
* The keyboard maintains its own internal caps lock and
|
||||
* num lock statuses. In caps lock mode E0 AA precedes make
|
||||
* code and E0 2A follows break code. In num lock mode,
|
||||
* E0 2A precedes make code and E0 AA follows break code.
|
||||
* We do our own book-keeping, so we will just ignore these.
|
||||
*/
|
||||
/*
|
||||
* For my keyboard there is no caps lock mode, but there are
|
||||
* both Shift-L and Shift-R modes. The former mode generates
|
||||
* E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
|
||||
* So, we should also ignore the latter. - aeb@cwi.nl
|
||||
*/
|
||||
if (scancode == 0x2a || scancode == 0x36)
|
||||
goto end_kbd_intr;
|
||||
|
||||
if (e0_keys[scancode])
|
||||
scancode = e0_keys[scancode];
|
||||
else if (!raw_mode) {
|
||||
printk("keyboard: unknown scancode e0 %02x\n", scancode);
|
||||
goto end_kbd_intr;
|
||||
}
|
||||
}
|
||||
} else if (scancode >= E0_BASE && !raw_mode) {
|
||||
printk("keyboard: scancode (%02x) not in range 00 - %2x\n",
|
||||
scancode, E0_BASE - 1);
|
||||
goto end_kbd_intr;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point the variable `scancode' contains the keysym.
|
||||
* We keep track of the up/down status of the key, and
|
||||
* return the keysym if in MEDIUMRAW mode.
|
||||
* (Note: earlier kernels had a bug and did not pass the up/down
|
||||
* bit to applications.)
|
||||
*/
|
||||
|
||||
if (up_flag) {
|
||||
clear_bit(scancode, key_down);
|
||||
rep = 0;
|
||||
} else
|
||||
rep = set_bit(scancode, key_down);
|
||||
|
||||
if (raw_mode)
|
||||
goto end_kbd_intr;
|
||||
|
||||
if (vc_kbd_mode(kbd, VC_MEDIUMRAW)) {
|
||||
put_queue(scancode + up_flag);
|
||||
goto end_kbd_intr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Small change in philosophy: earlier we defined repetition by
|
||||
* rep = scancode == prev_keysym;
|
||||
* prev_keysym = scancode;
|
||||
* but now by the fact that the depressed key was down already.
|
||||
* Does this ever make a difference?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Repeat a key only if the input buffers are empty or the
|
||||
* characters get echoed locally. This makes key repeat usable
|
||||
* with slow applications and under heavy loads.
|
||||
*/
|
||||
if (!rep ||
|
||||
(vc_kbd_mode(kbd,VC_REPEAT) && tty &&
|
||||
(L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q)))))
|
||||
{
|
||||
u_short key_code;
|
||||
u_char type;
|
||||
|
||||
/* the XOR below used to be an OR */
|
||||
int shift_final = shift_state ^ kbd->lockstate;
|
||||
|
||||
key_code = key_map[shift_final][scancode];
|
||||
type = KTYP(key_code);
|
||||
|
||||
if (type == KT_LETTER) {
|
||||
type = KT_LATIN;
|
||||
if (vc_kbd_led(kbd,VC_CAPSLOCK))
|
||||
key_code = key_map[shift_final ^ (1<<KG_SHIFT)][scancode];
|
||||
}
|
||||
(*key_handler[type])(key_code & 0xff, up_flag);
|
||||
}
|
||||
|
||||
end_kbd_intr:
|
||||
send_cmd(0xAE); /* enable keyboard */
|
||||
}
|
||||
|
||||
static void put_queue(int ch)
|
||||
{
|
||||
struct tty_queue *qp;
|
||||
|
||||
wake_up(&keypress_wait);
|
||||
if (!tty)
|
||||
return;
|
||||
qp = &tty->read_q;
|
||||
|
||||
if (LEFT(qp)) {
|
||||
qp->buf[qp->head] = ch;
|
||||
INC(qp->head);
|
||||
}
|
||||
}
|
||||
|
||||
static void puts_queue(char *cp)
|
||||
{
|
||||
struct tty_queue *qp;
|
||||
char ch;
|
||||
|
||||
/* why interruptible here, plain wake_up above? */
|
||||
wake_up_interruptible(&keypress_wait);
|
||||
if (!tty)
|
||||
return;
|
||||
qp = &tty->read_q;
|
||||
|
||||
while ((ch = *(cp++)) != 0) {
|
||||
if (LEFT(qp)) {
|
||||
qp->buf[qp->head] = ch;
|
||||
INC(qp->head);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void applkey(int key, char mode)
|
||||
{
|
||||
static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
|
||||
|
||||
buf[1] = (mode ? 'O' : '[');
|
||||
buf[2] = key;
|
||||
puts_queue(buf);
|
||||
}
|
||||
|
||||
static void enter(void)
|
||||
{
|
||||
put_queue(13);
|
||||
if (vc_kbd_mode(kbd,VC_CRLF))
|
||||
put_queue(10);
|
||||
}
|
||||
|
||||
static void caps_toggle(void)
|
||||
{
|
||||
if (rep)
|
||||
return;
|
||||
chg_vc_kbd_led(kbd,VC_CAPSLOCK);
|
||||
}
|
||||
|
||||
static void caps_on(void)
|
||||
{
|
||||
if (rep)
|
||||
return;
|
||||
set_vc_kbd_led(kbd,VC_CAPSLOCK);
|
||||
}
|
||||
|
||||
static void show_ptregs(void)
|
||||
{
|
||||
if (!pt_regs)
|
||||
return;
|
||||
printk("\n");
|
||||
printk("EIP: %04x:%08lx",0xffff & pt_regs->cs,pt_regs->eip);
|
||||
if (pt_regs->cs & 3)
|
||||
printk(" ESP: %04x:%08lx",0xffff & pt_regs->ss,pt_regs->esp);
|
||||
printk(" EFLAGS: %08lx\n",pt_regs->eflags);
|
||||
printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
|
||||
pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx);
|
||||
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
|
||||
pt_regs->esi, pt_regs->edi, pt_regs->ebp);
|
||||
printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
|
||||
0xffff & pt_regs->ds,0xffff & pt_regs->es,
|
||||
0xffff & pt_regs->fs,0xffff & pt_regs->gs);
|
||||
}
|
||||
|
||||
static void hold(void)
|
||||
{
|
||||
if (rep || !tty)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Note: SCROLLOCK wil be set (cleared) by stop_tty (start_tty);
|
||||
* these routines are also activated by ^S/^Q.
|
||||
* (And SCROLLOCK can also be set by the ioctl KDSETLED.)
|
||||
*/
|
||||
if (tty->stopped)
|
||||
start_tty(tty);
|
||||
else
|
||||
stop_tty(tty);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* unused at present - and the VC_PAUSE bit is not used anywhere either */
|
||||
static void pause(void)
|
||||
{
|
||||
chg_vc_kbd_mode(kbd,VC_PAUSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void num(void)
|
||||
{
|
||||
if (vc_kbd_mode(kbd,VC_APPLIC)) {
|
||||
applkey('P', 1);
|
||||
return;
|
||||
}
|
||||
if (!rep) /* no autorepeat for numlock, ChN */
|
||||
chg_vc_kbd_led(kbd,VC_NUMLOCK);
|
||||
}
|
||||
|
||||
static void lastcons(void)
|
||||
{
|
||||
/* pressing alt-printscreen switches to the last used console, ChN */
|
||||
want_console = last_console;
|
||||
}
|
||||
|
||||
static void send_intr(void)
|
||||
{
|
||||
got_break = 1;
|
||||
}
|
||||
|
||||
static void scrll_forw(void)
|
||||
{
|
||||
scrollfront(0);
|
||||
}
|
||||
|
||||
static void scrll_back(void)
|
||||
{
|
||||
scrollback(0);
|
||||
}
|
||||
|
||||
static void boot_it(void)
|
||||
{
|
||||
ctrl_alt_del();
|
||||
}
|
||||
|
||||
static void compose(void)
|
||||
{
|
||||
dead_key_next = 1;
|
||||
}
|
||||
|
||||
static void do_spec(unsigned char value, char up_flag)
|
||||
{
|
||||
typedef void (*fnp)(void);
|
||||
fnp fn_table[] = {
|
||||
NULL, enter, show_ptregs, show_mem,
|
||||
show_state, send_intr, lastcons, caps_toggle,
|
||||
num, hold, scrll_forw, scrll_back,
|
||||
boot_it, caps_on, compose
|
||||
};
|
||||
|
||||
if (up_flag)
|
||||
return;
|
||||
if (value >= SIZE(fn_table))
|
||||
return;
|
||||
if (!fn_table[value])
|
||||
return;
|
||||
fn_table[value]();
|
||||
}
|
||||
|
||||
static void do_lowercase(unsigned char value, char up_flag)
|
||||
{
|
||||
printk("keyboard.c: do_lowercase was called - impossible\n");
|
||||
}
|
||||
|
||||
static void do_self(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return; /* no action, if this is a key release */
|
||||
|
||||
if (diacr)
|
||||
value = handle_diacr(value);
|
||||
|
||||
if (dead_key_next) {
|
||||
dead_key_next = 0;
|
||||
diacr = value;
|
||||
return;
|
||||
}
|
||||
|
||||
put_queue(value);
|
||||
}
|
||||
|
||||
#define A_GRAVE '`'
|
||||
#define A_ACUTE '\''
|
||||
#define A_CFLEX '^'
|
||||
#define A_TILDE '~'
|
||||
#define A_DIAER '"'
|
||||
static unsigned char ret_diacr[] =
|
||||
{A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
|
||||
|
||||
/* If a dead key pressed twice, output a character corresponding to it, */
|
||||
/* otherwise just remember the dead key. */
|
||||
|
||||
static void do_dead(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
value = ret_diacr[value];
|
||||
if (diacr == value) { /* pressed twice */
|
||||
diacr = 0;
|
||||
put_queue(value);
|
||||
return;
|
||||
}
|
||||
diacr = value;
|
||||
}
|
||||
|
||||
|
||||
/* If space is pressed, return the character corresponding the pending */
|
||||
/* dead key, otherwise try to combine the two. */
|
||||
|
||||
unsigned char handle_diacr(unsigned char ch)
|
||||
{
|
||||
int d = diacr;
|
||||
int i;
|
||||
|
||||
diacr = 0;
|
||||
if (ch == ' ')
|
||||
return d;
|
||||
|
||||
for (i = 0; i < accent_table_size; i++)
|
||||
if(accent_table[i].diacr == d && accent_table[i].base == ch)
|
||||
return accent_table[i].result;
|
||||
|
||||
put_queue(d);
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void do_cons(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
want_console = value;
|
||||
}
|
||||
|
||||
static void do_fn(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
if (value < SIZE(func_table))
|
||||
puts_queue(func_table[value]);
|
||||
else
|
||||
printk("do_fn called with value=%d\n", value);
|
||||
}
|
||||
|
||||
static void do_pad(unsigned char value, char up_flag)
|
||||
{
|
||||
static char *pad_chars = "0123456789+-*/\015,.?";
|
||||
static char *app_map = "pqrstuvwxylSRQMnn?";
|
||||
|
||||
if (up_flag)
|
||||
return; /* no action, if this is a key release */
|
||||
|
||||
/* kludge... shift forces cursor/number keys */
|
||||
if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
|
||||
applkey(app_map[value], 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vc_kbd_led(kbd,VC_NUMLOCK))
|
||||
switch (value) {
|
||||
case KVAL(K_PCOMMA):
|
||||
case KVAL(K_PDOT):
|
||||
do_fn(KVAL(K_REMOVE), 0);
|
||||
return;
|
||||
case KVAL(K_P0):
|
||||
do_fn(KVAL(K_INSERT), 0);
|
||||
return;
|
||||
case KVAL(K_P1):
|
||||
do_fn(KVAL(K_SELECT), 0);
|
||||
return;
|
||||
case KVAL(K_P2):
|
||||
do_cur(KVAL(K_DOWN), 0);
|
||||
return;
|
||||
case KVAL(K_P3):
|
||||
do_fn(KVAL(K_PGDN), 0);
|
||||
return;
|
||||
case KVAL(K_P4):
|
||||
do_cur(KVAL(K_LEFT), 0);
|
||||
return;
|
||||
case KVAL(K_P6):
|
||||
do_cur(KVAL(K_RIGHT), 0);
|
||||
return;
|
||||
case KVAL(K_P7):
|
||||
do_fn(KVAL(K_FIND), 0);
|
||||
return;
|
||||
case KVAL(K_P8):
|
||||
do_cur(KVAL(K_UP), 0);
|
||||
return;
|
||||
case KVAL(K_P9):
|
||||
do_fn(KVAL(K_PGUP), 0);
|
||||
return;
|
||||
case KVAL(K_P5):
|
||||
applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
|
||||
return;
|
||||
}
|
||||
|
||||
put_queue(pad_chars[value]);
|
||||
if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
|
||||
put_queue(10);
|
||||
}
|
||||
|
||||
static void do_cur(unsigned char value, char up_flag)
|
||||
{
|
||||
static char *cur_chars = "BDCA";
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
|
||||
}
|
||||
|
||||
static void do_shift(unsigned char value, char up_flag)
|
||||
{
|
||||
int old_state = shift_state;
|
||||
|
||||
if (rep)
|
||||
return;
|
||||
|
||||
/* kludge... */
|
||||
if (value == KVAL(K_CAPSSHIFT)) {
|
||||
value = KVAL(K_SHIFT);
|
||||
clr_vc_kbd_led(kbd, VC_CAPSLOCK);
|
||||
}
|
||||
|
||||
if (up_flag) {
|
||||
/* handle the case that two shift or control
|
||||
keys are depressed simultaneously */
|
||||
if (k_down[value])
|
||||
k_down[value]--;
|
||||
} else
|
||||
k_down[value]++;
|
||||
|
||||
if (k_down[value])
|
||||
shift_state |= (1 << value);
|
||||
else
|
||||
shift_state &= ~ (1 << value);
|
||||
|
||||
/* kludge */
|
||||
if (up_flag && shift_state != old_state && npadch != -1) {
|
||||
put_queue(npadch);
|
||||
npadch = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* called after returning from RAW mode or when changing consoles -
|
||||
recompute k_down[] and shift_state from key_down[] */
|
||||
void compute_shiftstate(void)
|
||||
{
|
||||
int i, j, k, sym, val;
|
||||
|
||||
shift_state = 0;
|
||||
for(i=0; i < SIZE(k_down); i++)
|
||||
k_down[i] = 0;
|
||||
|
||||
for(i=0; i < SIZE(key_down); i++)
|
||||
if(key_down[i]) { /* skip this word if not a single bit on */
|
||||
k = (i<<5);
|
||||
for(j=0; j<32; j++,k++)
|
||||
if(test_bit(k, key_down)) {
|
||||
sym = key_map[0][k];
|
||||
if(KTYP(sym) == KT_SHIFT) {
|
||||
val = KVAL(sym);
|
||||
k_down[val]++;
|
||||
shift_state |= (1<<val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_meta(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
if (vc_kbd_mode(kbd, VC_META)) {
|
||||
put_queue('\033');
|
||||
put_queue(value);
|
||||
} else
|
||||
put_queue(value | 0x80);
|
||||
}
|
||||
|
||||
static void do_ascii(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
if (npadch == -1)
|
||||
npadch = value;
|
||||
else
|
||||
npadch = (npadch * 10 + value) % 1000;
|
||||
}
|
||||
|
||||
static void do_lock(unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag || rep)
|
||||
return;
|
||||
chg_vc_kbd_lock(kbd, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* send_data sends a character to the keyboard and waits
|
||||
* for a acknowledge, possibly retrying if asked to. Returns
|
||||
* the success status.
|
||||
*/
|
||||
static int send_data(unsigned char data)
|
||||
{
|
||||
int retries = 3;
|
||||
int i;
|
||||
|
||||
do {
|
||||
kb_wait();
|
||||
acknowledge = 0;
|
||||
resend = 0;
|
||||
outb_p(data, 0x60);
|
||||
for(i=0; i<0x20000; i++) {
|
||||
inb_p(0x64); /* just as a delay */
|
||||
if (acknowledge)
|
||||
return 1;
|
||||
if (resend)
|
||||
break;
|
||||
}
|
||||
if (!resend)
|
||||
return 0;
|
||||
} while (retries-- > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is the bottom half of the keyboard interrupt
|
||||
* routine, and runs with all interrupts enabled. It does
|
||||
* console changing, led setting and copy_to_cooked, which can
|
||||
* take a reasonably long time.
|
||||
*
|
||||
* Aside from timing (which isn't really that important for
|
||||
* keyboard interrupts as they happen often), using the software
|
||||
* interrupt routines for this thing allows us to easily mask
|
||||
* this when we don't want any of the above to happen. Not yet
|
||||
* used, but this allows for easy and efficient race-condition
|
||||
* prevention later on.
|
||||
*/
|
||||
static void kbd_bh(void * unused)
|
||||
{
|
||||
static unsigned char old_leds = 0xff;
|
||||
unsigned char leds = kbd_table[fg_console].ledstate;
|
||||
|
||||
if (leds != old_leds) {
|
||||
old_leds = leds;
|
||||
if (!send_data(0xed) || !send_data(leds))
|
||||
send_data(0xf4); /* re-enable kbd if any errors */
|
||||
}
|
||||
if (want_console >= 0) {
|
||||
if (want_console != fg_console) {
|
||||
last_console = fg_console;
|
||||
change_console(want_console);
|
||||
}
|
||||
want_console = -1;
|
||||
}
|
||||
if (got_break) {
|
||||
if (tty && !I_IGNBRK(tty)) {
|
||||
if (I_BRKINT(tty)) {
|
||||
flush_input(tty);
|
||||
flush_output(tty);
|
||||
if (tty->pgrp > 0)
|
||||
kill_pg(tty->pgrp, SIGINT, 1);
|
||||
} else {
|
||||
cli();
|
||||
if (LEFT(&tty->read_q) >= 2) {
|
||||
set_bit(tty->read_q.head,
|
||||
&tty->readq_flags);
|
||||
put_queue(TTY_BREAK);
|
||||
put_queue(0);
|
||||
}
|
||||
sti();
|
||||
}
|
||||
}
|
||||
got_break = 0;
|
||||
}
|
||||
do_keyboard_interrupt();
|
||||
cli();
|
||||
if ((inb_p(0x64) & kbd_read_mask) == 0x01)
|
||||
fake_keyboard_interrupt();
|
||||
sti();
|
||||
}
|
||||
|
||||
long no_idt[2] = {0, 0};
|
||||
|
||||
/*
|
||||
* This routine reboots the machine by asking the keyboard
|
||||
* controller to pulse the reset-line low. We try that for a while,
|
||||
* and if it doesn't work, we do some other stupid things.
|
||||
*/
|
||||
void hard_reset_now(void)
|
||||
{
|
||||
int i, j;
|
||||
extern unsigned long pg0[1024];
|
||||
|
||||
sti();
|
||||
/* rebooting needs to touch the page at absolute addr 0 */
|
||||
pg0[0] = 7;
|
||||
*((unsigned short *)0x472) = 0x1234;
|
||||
for (;;) {
|
||||
for (i=0; i<100; i++) {
|
||||
kb_wait();
|
||||
for(j = 0; j < 100000 ; j++)
|
||||
/* nothing */;
|
||||
outb(0xfe,0x64); /* pulse reset low */
|
||||
}
|
||||
__asm__("\tlidt _no_idt");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long kbd_init(unsigned long kmem_start)
|
||||
{
|
||||
int i;
|
||||
struct kbd_struct * kbd;
|
||||
|
||||
kbd = kbd_table + 0;
|
||||
for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) {
|
||||
kbd->ledstate = KBD_DEFLEDS;
|
||||
kbd->default_ledstate = KBD_DEFLEDS;
|
||||
kbd->lockstate = KBD_DEFLOCK;
|
||||
kbd->modeflags = KBD_DEFMODE;
|
||||
}
|
||||
|
||||
bh_base[KEYBOARD_BH].routine = kbd_bh;
|
||||
request_irq(KEYBOARD_IRQ,keyboard_interrupt);
|
||||
mark_bh(KEYBOARD_BH);
|
||||
return kmem_start;
|
||||
}
|
461
source/THIRDPARTY/linux-old/drivers/char/lp.c
Normal file
461
source/THIRDPARTY/linux-old/drivers/char/lp.c
Normal file
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* Copyright (C) 1992 by Jim Weigand and Linus Torvalds
|
||||
* Copyright (C) 1992,1993 by Michael K. Johnson
|
||||
* - Thanks much to Gunter Windau for pointing out to me where the error
|
||||
* checking ought to be.
|
||||
* Copyright (C) 1993 by Nigel Gamble (added interrupt code)
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/lp.h>
|
||||
#include <linux/malloc.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* All my debugging code assumes that you debug with only one printer at
|
||||
* a time. RWWH
|
||||
*/
|
||||
|
||||
#undef LP_DEBUG
|
||||
|
||||
static int lp_reset(int minor)
|
||||
{
|
||||
int testvalue;
|
||||
unsigned char command;
|
||||
|
||||
command = LP_PSELECP | LP_PINITP;
|
||||
|
||||
/* reset value */
|
||||
outb_p(0, LP_C(minor));
|
||||
for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
|
||||
;
|
||||
outb_p(command, LP_C(minor));
|
||||
return LP_S(minor);
|
||||
}
|
||||
|
||||
#ifdef LP_DEBUG
|
||||
static int lp_max_count = 1;
|
||||
#endif
|
||||
|
||||
static int lp_char_polled(char lpchar, int minor)
|
||||
{
|
||||
int status = 0, wait = 0;
|
||||
unsigned long count = 0;
|
||||
|
||||
do {
|
||||
status = LP_S(minor);
|
||||
count ++;
|
||||
if(need_resched)
|
||||
schedule();
|
||||
} while(!(status & LP_PBUSY) && count < LP_CHAR(minor));
|
||||
|
||||
if (count == LP_CHAR(minor)) {
|
||||
return 0;
|
||||
/* we timed out, and the character was /not/ printed */
|
||||
}
|
||||
#ifdef LP_DEBUG
|
||||
if (count > lp_max_count) {
|
||||
printk("lp success after %d counts.\n",count);
|
||||
lp_max_count=count;
|
||||
}
|
||||
#endif
|
||||
outb_p(lpchar, LP_B(minor));
|
||||
/* must wait before taking strobe high, and after taking strobe
|
||||
low, according spec. Some printers need it, others don't. */
|
||||
while(wait != LP_WAIT(minor)) wait++;
|
||||
/* control port takes strobe high */
|
||||
outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
|
||||
while(wait) wait--;
|
||||
/* take strobe low */
|
||||
outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lp_char_interrupt(char lpchar, int minor)
|
||||
{
|
||||
int wait = 0;
|
||||
unsigned char status;
|
||||
|
||||
|
||||
if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
|
||||
|| !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
|
||||
|| !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
|
||||
|
||||
outb_p(lpchar, LP_B(minor));
|
||||
/* must wait before taking strobe high, and after taking strobe
|
||||
low, according spec. Some printers need it, others don't. */
|
||||
while(wait != LP_WAIT(minor)) wait++;
|
||||
/* control port takes strobe high */
|
||||
outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
|
||||
while(wait) wait--;
|
||||
/* take strobe low */
|
||||
outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LP_DEBUG
|
||||
unsigned int lp_total_chars = 0;
|
||||
unsigned int lp_last_call = 0;
|
||||
#endif
|
||||
|
||||
static void lp_interrupt(int irq)
|
||||
{
|
||||
struct lp_struct *lp = &lp_table[0];
|
||||
struct lp_struct *lp_end = &lp_table[LP_NO];
|
||||
|
||||
while (irq != lp->irq) {
|
||||
if (++lp >= lp_end)
|
||||
return;
|
||||
}
|
||||
|
||||
wake_up(&lp->lp_wait_q);
|
||||
}
|
||||
|
||||
static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
unsigned long copy_size;
|
||||
unsigned long total_bytes_written = 0;
|
||||
unsigned long bytes_written;
|
||||
struct lp_struct *lp = &lp_table[minor];
|
||||
unsigned char status;
|
||||
|
||||
do {
|
||||
bytes_written = 0;
|
||||
copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
|
||||
memcpy_fromfs(lp->lp_buffer, buf, copy_size);
|
||||
|
||||
while (copy_size) {
|
||||
if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
|
||||
--copy_size;
|
||||
++bytes_written;
|
||||
} else {
|
||||
if (!((status = LP_S(minor)) & LP_PERRORP)) {
|
||||
int rc = total_bytes_written + bytes_written;
|
||||
|
||||
if ((status & LP_POUTPA)) {
|
||||
printk("lp%d out of paper\n", minor);
|
||||
if (!rc)
|
||||
rc = -ENOSPC;
|
||||
} else if (!(status & LP_PSELECD)) {
|
||||
printk("lp%d off-line\n", minor);
|
||||
if (!rc)
|
||||
rc = -EIO;
|
||||
} else {
|
||||
printk("lp%d printer error\n", minor);
|
||||
if (!rc)
|
||||
rc = -EIO;
|
||||
}
|
||||
if(LP_F(minor) & LP_ABORT)
|
||||
return rc;
|
||||
}
|
||||
cli();
|
||||
outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
|
||||
status = LP_S(minor);
|
||||
if (!(status & LP_PACK) || (status & LP_PBUSY)) {
|
||||
outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
|
||||
sti();
|
||||
continue;
|
||||
}
|
||||
current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
|
||||
interruptible_sleep_on(&lp->lp_wait_q);
|
||||
outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
|
||||
if (current->signal & ~current->blocked) {
|
||||
if (total_bytes_written + bytes_written)
|
||||
return total_bytes_written + bytes_written;
|
||||
else
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total_bytes_written += bytes_written;
|
||||
buf += bytes_written;
|
||||
count -= bytes_written;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
static int lp_write_polled(struct inode * inode, struct file * file,
|
||||
char * buf, int count)
|
||||
{
|
||||
int retval;
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
char c, *temp = buf;
|
||||
|
||||
#ifdef LP_DEBUG
|
||||
if (jiffies-lp_last_call > LP_TIME(minor)) {
|
||||
lp_total_chars = 0;
|
||||
lp_max_count = 1;
|
||||
}
|
||||
lp_last_call = jiffies;
|
||||
#endif
|
||||
|
||||
temp = buf;
|
||||
while (count > 0) {
|
||||
c = get_fs_byte(temp);
|
||||
retval = lp_char_polled(c, minor);
|
||||
/* only update counting vars if character was printed */
|
||||
if (retval) { count--; temp++;
|
||||
#ifdef LP_DEBUG
|
||||
lp_total_chars++;
|
||||
#endif
|
||||
}
|
||||
if (!retval) { /* if printer timed out */
|
||||
int status = LP_S(minor);
|
||||
|
||||
if (status & LP_POUTPA) {
|
||||
printk("lp%d out of paper\n", minor);
|
||||
if(LP_F(minor) & LP_ABORT)
|
||||
return temp-buf?temp-buf:-ENOSPC;
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||||
schedule();
|
||||
} else
|
||||
if (!(status & LP_PSELECD)) {
|
||||
printk("lp%d off-line\n", minor);
|
||||
if(LP_F(minor) & LP_ABORT)
|
||||
return temp-buf?temp-buf:-EIO;
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||||
schedule();
|
||||
} else
|
||||
/* not offline or out of paper. on fire? */
|
||||
if (!(status & LP_PERRORP)) {
|
||||
printk("lp%d on fire\n", minor);
|
||||
if(LP_F(minor) & LP_ABORT)
|
||||
return temp-buf?temp-buf:-EFAULT;
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||||
schedule();
|
||||
}
|
||||
|
||||
/* check for signals before going to sleep */
|
||||
if (current->signal & ~current->blocked) {
|
||||
if (temp != buf)
|
||||
return temp-buf;
|
||||
else
|
||||
return -EINTR;
|
||||
}
|
||||
#ifdef LP_DEBUG
|
||||
printk("lp sleeping at %d characters for %d jiffies\n",
|
||||
lp_total_chars, LP_TIME(minor));
|
||||
lp_total_chars=0;
|
||||
#endif
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + LP_TIME(minor);
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
return temp-buf;
|
||||
}
|
||||
|
||||
static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
|
||||
{
|
||||
if (LP_IRQ(MINOR(inode->i_rdev)))
|
||||
return lp_write_interrupt(inode, file, buf, count);
|
||||
else
|
||||
return lp_write_polled(inode, file, buf, count);
|
||||
}
|
||||
|
||||
static int lp_lseek(struct inode * inode, struct file * file,
|
||||
off_t offset, int origin)
|
||||
{
|
||||
return -ESPIPE;
|
||||
}
|
||||
|
||||
static int lp_open(struct inode * inode, struct file * file)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
int ret;
|
||||
unsigned int irq;
|
||||
struct sigaction sa;
|
||||
|
||||
if (minor >= LP_NO)
|
||||
return -ENODEV;
|
||||
if ((LP_F(minor) & LP_EXIST) == 0)
|
||||
return -ENODEV;
|
||||
if (LP_F(minor) & LP_BUSY)
|
||||
return -EBUSY;
|
||||
|
||||
if ((irq = LP_IRQ(minor))) {
|
||||
lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!lp_table[minor].lp_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
sa.sa_handler = lp_interrupt;
|
||||
sa.sa_flags = SA_INTERRUPT;
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_restorer = NULL;
|
||||
ret = irqaction(irq, &sa);
|
||||
if (ret) {
|
||||
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
|
||||
lp_table[minor].lp_buffer = NULL;
|
||||
printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
LP_F(minor) |= LP_BUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lp_release(struct inode * inode, struct file * file)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
unsigned int irq;
|
||||
|
||||
if ((irq = LP_IRQ(minor))) {
|
||||
free_irq(irq);
|
||||
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
|
||||
lp_table[minor].lp_buffer = NULL;
|
||||
}
|
||||
|
||||
LP_F(minor) &= ~LP_BUSY;
|
||||
}
|
||||
|
||||
|
||||
static int lp_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
int retval = 0;
|
||||
|
||||
#ifdef LP_DEBUG
|
||||
printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
|
||||
#endif
|
||||
if (minor >= LP_NO)
|
||||
return -ENODEV;
|
||||
if ((LP_F(minor) & LP_EXIST) == 0)
|
||||
return -ENODEV;
|
||||
switch ( cmd ) {
|
||||
case LPTIME:
|
||||
LP_TIME(minor) = arg;
|
||||
break;
|
||||
case LPCHAR:
|
||||
LP_CHAR(minor) = arg;
|
||||
break;
|
||||
case LPABORT:
|
||||
if (arg)
|
||||
LP_F(minor) |= LP_ABORT;
|
||||
else
|
||||
LP_F(minor) &= ~LP_ABORT;
|
||||
break;
|
||||
case LPWAIT:
|
||||
LP_WAIT(minor) = arg;
|
||||
break;
|
||||
case LPSETIRQ: {
|
||||
int oldirq;
|
||||
int newirq = arg;
|
||||
struct lp_struct *lp = &lp_table[minor];
|
||||
struct sigaction sa;
|
||||
|
||||
if (!suser())
|
||||
return -EPERM;
|
||||
|
||||
oldirq = LP_IRQ(minor);
|
||||
|
||||
/* Allocate buffer now if we are going to need it */
|
||||
if (!oldirq && newirq) {
|
||||
lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!lp->lp_buffer)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (oldirq) {
|
||||
free_irq(oldirq);
|
||||
}
|
||||
if (newirq) {
|
||||
/* Install new irq */
|
||||
sa.sa_handler = lp_interrupt;
|
||||
sa.sa_flags = SA_INTERRUPT;
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_restorer = NULL;
|
||||
if ((retval = irqaction(newirq, &sa))) {
|
||||
if (oldirq) {
|
||||
/* restore old irq */
|
||||
irqaction(oldirq, &sa);
|
||||
} else {
|
||||
/* We don't need the buffer */
|
||||
kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
|
||||
lp->lp_buffer = NULL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
if (oldirq && !newirq) {
|
||||
/* We don't need the buffer */
|
||||
kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
|
||||
lp->lp_buffer = NULL;
|
||||
}
|
||||
LP_IRQ(minor) = newirq;
|
||||
lp_reset(minor);
|
||||
break;
|
||||
}
|
||||
case LPGETIRQ:
|
||||
retval = LP_IRQ(minor);
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static struct file_operations lp_fops = {
|
||||
lp_lseek,
|
||||
NULL, /* lp_read */
|
||||
lp_write,
|
||||
NULL, /* lp_readdir */
|
||||
NULL, /* lp_select */
|
||||
lp_ioctl,
|
||||
NULL, /* lp_mmap */
|
||||
lp_open,
|
||||
lp_release
|
||||
};
|
||||
|
||||
long lp_init(long kmem_start)
|
||||
{
|
||||
int offset = 0;
|
||||
unsigned int testvalue = 0;
|
||||
int count = 0;
|
||||
|
||||
if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
|
||||
printk("unable to get major %d for line printer\n", LP_MAJOR);
|
||||
return kmem_start;
|
||||
}
|
||||
/* take on all known port values */
|
||||
for (offset = 0; offset < LP_NO; offset++) {
|
||||
/* write to port & read back to check */
|
||||
outb_p( LP_DUMMY, LP_B(offset));
|
||||
for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
|
||||
;
|
||||
testvalue = inb_p(LP_B(offset));
|
||||
if (testvalue != 255) {
|
||||
LP_F(offset) |= LP_EXIST;
|
||||
lp_reset(offset);
|
||||
printk("lp_init: lp%d exists (%d), ", offset, testvalue);
|
||||
if (LP_IRQ(offset))
|
||||
printk("using IRQ%d\n", LP_IRQ(offset));
|
||||
else
|
||||
printk("using polling driver\n");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0)
|
||||
printk("lp_init: no lp devices found\n");
|
||||
return kmem_start;
|
||||
}
|
426
source/THIRDPARTY/linux-old/drivers/char/mem.c
Normal file
426
source/THIRDPARTY/linux-old/drivers/char/mem.c
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* linux/kernel/chr_drv/mem.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/mouse.h>
|
||||
#include <linux/tpqic02.h>
|
||||
#include <linux/malloc.h>
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include <asm/segment.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef CONFIG_SOUND
|
||||
extern long soundcard_init(long mem_start);
|
||||
#endif
|
||||
|
||||
static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
|
||||
{
|
||||
unsigned long p = file->f_pos;
|
||||
int read;
|
||||
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
if (p >= high_memory)
|
||||
return 0;
|
||||
if (count > high_memory - p)
|
||||
count = high_memory - p;
|
||||
read = 0;
|
||||
while (p < PAGE_SIZE && count > 0) {
|
||||
put_fs_byte(0,buf);
|
||||
buf++;
|
||||
p++;
|
||||
count--;
|
||||
read++;
|
||||
}
|
||||
memcpy_tofs(buf,(void *) p,count);
|
||||
read += count;
|
||||
file->f_pos += read;
|
||||
return read;
|
||||
}
|
||||
|
||||
static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
|
||||
{
|
||||
unsigned long p = file->f_pos;
|
||||
int written;
|
||||
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
if (p >= high_memory)
|
||||
return 0;
|
||||
if (count > high_memory - p)
|
||||
count = high_memory - p;
|
||||
written = 0;
|
||||
while (p < PAGE_SIZE && count > 0) {
|
||||
/* Hmm. Do something? */
|
||||
buf++;
|
||||
p++;
|
||||
count--;
|
||||
written++;
|
||||
}
|
||||
memcpy_fromfs((void *) p,buf,count);
|
||||
written += count;
|
||||
file->f_pos += written;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mmap_mem(struct inode * inode, struct file * file,
|
||||
unsigned long addr, size_t len, int prot, unsigned long off)
|
||||
{
|
||||
struct vm_area_struct * mpnt;
|
||||
|
||||
if (off & 0xfff || off + len < off)
|
||||
return -ENXIO;
|
||||
if (x86 > 3 && off >= high_memory)
|
||||
prot |= PAGE_PCD;
|
||||
if (remap_page_range(addr, off, len, prot))
|
||||
return -EAGAIN;
|
||||
/* try to create a dummy vmm-structure so that the rest of the kernel knows we are here */
|
||||
mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
|
||||
if (!mpnt)
|
||||
return 0;
|
||||
|
||||
mpnt->vm_task = current;
|
||||
mpnt->vm_start = addr;
|
||||
mpnt->vm_end = addr + len;
|
||||
mpnt->vm_page_prot = prot;
|
||||
mpnt->vm_share = NULL;
|
||||
mpnt->vm_inode = inode;
|
||||
inode->i_count++;
|
||||
mpnt->vm_offset = off;
|
||||
mpnt->vm_ops = NULL;
|
||||
insert_vm_struct(current, mpnt);
|
||||
merge_segments(current->mmap, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
|
||||
{
|
||||
int read1, read2;
|
||||
|
||||
read1 = read_mem(inode, file, buf, count);
|
||||
if (read1 < 0)
|
||||
return read1;
|
||||
read2 = vread(buf + read1, (char *) file->f_pos, count - read1);
|
||||
if (read2 < 0)
|
||||
return read2;
|
||||
file->f_pos += read2;
|
||||
return read1 + read2;
|
||||
}
|
||||
|
||||
static int read_port(struct inode * inode,struct file * file,char * buf, int count)
|
||||
{
|
||||
unsigned int i = file->f_pos;
|
||||
char * tmp = buf;
|
||||
|
||||
while (count-- > 0 && i < 65536) {
|
||||
put_fs_byte(inb(i),tmp);
|
||||
i++;
|
||||
tmp++;
|
||||
}
|
||||
file->f_pos = i;
|
||||
return tmp-buf;
|
||||
}
|
||||
|
||||
static int write_port(struct inode * inode,struct file * file,char * buf, int count)
|
||||
{
|
||||
unsigned int i = file->f_pos;
|
||||
char * tmp = buf;
|
||||
|
||||
while (count-- > 0 && i < 65536) {
|
||||
outb(get_fs_byte(tmp),i);
|
||||
i++;
|
||||
tmp++;
|
||||
}
|
||||
file->f_pos = i;
|
||||
return tmp-buf;
|
||||
}
|
||||
|
||||
static int read_null(struct inode * node,struct file * file,char * buf,int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_null(struct inode * inode,struct file * file,char * buf, int count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
static int read_zero(struct inode * node,struct file * file,char * buf,int count)
|
||||
{
|
||||
int left;
|
||||
|
||||
for (left = count; left > 0; left--) {
|
||||
put_fs_byte(0,buf);
|
||||
buf++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mmap_zero(struct inode * inode, struct file * file,
|
||||
unsigned long addr, size_t len, int prot, unsigned long off)
|
||||
{
|
||||
struct vm_area_struct *mpnt;
|
||||
|
||||
if (prot & PAGE_RW)
|
||||
return -EINVAL;
|
||||
if (zeromap_page_range(addr, len, prot))
|
||||
return -EAGAIN;
|
||||
/*
|
||||
* try to create a dummy vmm-structure so that the
|
||||
* rest of the kernel knows we are here
|
||||
*/
|
||||
mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
|
||||
if (!mpnt)
|
||||
return 0;
|
||||
|
||||
mpnt->vm_task = current;
|
||||
mpnt->vm_start = addr;
|
||||
mpnt->vm_end = addr + len;
|
||||
mpnt->vm_page_prot = prot;
|
||||
mpnt->vm_share = NULL;
|
||||
mpnt->vm_inode = NULL;
|
||||
mpnt->vm_offset = off;
|
||||
mpnt->vm_ops = NULL;
|
||||
insert_vm_struct(current, mpnt);
|
||||
merge_segments(current->mmap, ignoff_mergep, inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_full(struct inode * node,struct file * file,char * buf,int count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
static int write_full(struct inode * inode,struct file * file,char * buf, int count)
|
||||
{
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special lseek() function for /dev/null and /dev/zero. Most notably, you can fopen()
|
||||
* both devices with "a" now. This was previously impossible. SRB.
|
||||
*/
|
||||
|
||||
static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
|
||||
{
|
||||
return file->f_pos=0;
|
||||
}
|
||||
/*
|
||||
* The memory devices use the full 32 bits of the offset, and so we cannot
|
||||
* check against negative addresses: they are ok. The return value is weird,
|
||||
* though, in that case (0).
|
||||
*
|
||||
* also note that seeking relative to the "end of file" isn't supported:
|
||||
* it has no meaning, so it returns -EINVAL.
|
||||
*/
|
||||
static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
|
||||
{
|
||||
switch (orig) {
|
||||
case 0:
|
||||
file->f_pos = offset;
|
||||
return file->f_pos;
|
||||
case 1:
|
||||
file->f_pos += offset;
|
||||
return file->f_pos;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (file->f_pos < 0)
|
||||
return 0;
|
||||
return file->f_pos;
|
||||
}
|
||||
|
||||
#define write_kmem write_mem
|
||||
#define mmap_kmem mmap_mem
|
||||
#define zero_lseek null_lseek
|
||||
#define write_zero write_null
|
||||
|
||||
static struct file_operations ram_fops = {
|
||||
memory_lseek,
|
||||
read_ram,
|
||||
write_ram,
|
||||
NULL, /* ram_readdir */
|
||||
NULL, /* ram_select */
|
||||
NULL, /* ram_ioctl */
|
||||
NULL, /* ram_mmap */
|
||||
NULL, /* no special open code */
|
||||
NULL, /* no special release code */
|
||||
NULL /* fsync */
|
||||
};
|
||||
|
||||
static struct file_operations mem_fops = {
|
||||
memory_lseek,
|
||||
read_mem,
|
||||
write_mem,
|
||||
NULL, /* mem_readdir */
|
||||
NULL, /* mem_select */
|
||||
NULL, /* mem_ioctl */
|
||||
mmap_mem,
|
||||
NULL, /* no special open code */
|
||||
NULL, /* no special release code */
|
||||
NULL /* fsync */
|
||||
};
|
||||
|
||||
static struct file_operations kmem_fops = {
|
||||
memory_lseek,
|
||||
read_kmem,
|
||||
write_kmem,
|
||||
NULL, /* kmem_readdir */
|
||||
NULL, /* kmem_select */
|
||||
NULL, /* kmem_ioctl */
|
||||
mmap_kmem,
|
||||
NULL, /* no special open code */
|
||||
NULL, /* no special release code */
|
||||
NULL /* fsync */
|
||||
};
|
||||
|
||||
static struct file_operations null_fops = {
|
||||
null_lseek,
|
||||
read_null,
|
||||
write_null,
|
||||
NULL, /* null_readdir */
|
||||
NULL, /* null_select */
|
||||
NULL, /* null_ioctl */
|
||||
NULL, /* null_mmap */
|
||||
NULL, /* no special open code */
|
||||
NULL, /* no special release code */
|
||||
NULL /* fsync */
|
||||
};
|
||||
|
||||
static struct file_operations port_fops = {
|
||||
memory_lseek,
|
||||
read_port,
|
||||
write_port,
|
||||
NULL, /* port_readdir */
|
||||
NULL, /* port_select */
|
||||
NULL, /* port_ioctl */
|
||||
NULL, /* port_mmap */
|
||||
NULL, /* no special open code */
|
||||
NULL, /* no special release code */
|
||||
NULL /* fsync */
|
||||
};
|
||||
|
||||
static struct file_operations zero_fops = {
|
||||
zero_lseek,
|
||||
read_zero,
|
||||
write_zero,
|
||||
NULL, /* zero_readdir */
|
||||
NULL, /* zero_select */
|
||||
NULL, /* zero_ioctl */
|
||||
mmap_zero,
|
||||
NULL, /* no special open code */
|
||||
NULL /* no special release code */
|
||||
};
|
||||
|
||||
static struct file_operations full_fops = {
|
||||
memory_lseek,
|
||||
read_full,
|
||||
write_full,
|
||||
NULL, /* full_readdir */
|
||||
NULL, /* full_select */
|
||||
NULL, /* full_ioctl */
|
||||
NULL, /* full_mmap */
|
||||
NULL, /* no special open code */
|
||||
NULL /* no special release code */
|
||||
};
|
||||
|
||||
static int memory_open(struct inode * inode, struct file * filp)
|
||||
{
|
||||
switch (MINOR(inode->i_rdev)) {
|
||||
case 0:
|
||||
filp->f_op = &ram_fops;
|
||||
break;
|
||||
case 1:
|
||||
filp->f_op = &mem_fops;
|
||||
break;
|
||||
case 2:
|
||||
filp->f_op = &kmem_fops;
|
||||
break;
|
||||
case 3:
|
||||
filp->f_op = &null_fops;
|
||||
break;
|
||||
case 4:
|
||||
filp->f_op = &port_fops;
|
||||
break;
|
||||
case 5:
|
||||
filp->f_op = &zero_fops;
|
||||
break;
|
||||
case 7:
|
||||
filp->f_op = &full_fops;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
if (filp->f_op && filp->f_op->open)
|
||||
return filp->f_op->open(inode,filp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations memory_fops = {
|
||||
NULL, /* lseek */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* readdir */
|
||||
NULL, /* select */
|
||||
NULL, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
memory_open, /* just a selector for the real open */
|
||||
NULL, /* release */
|
||||
NULL /* fsync */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FTAPE
|
||||
char* ftape_big_buffer;
|
||||
#endif
|
||||
|
||||
long chr_dev_init(long mem_start, long mem_end)
|
||||
{
|
||||
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
|
||||
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
|
||||
mem_start = tty_init(mem_start);
|
||||
#ifdef CONFIG_PRINTER
|
||||
mem_start = lp_init(mem_start);
|
||||
#endif
|
||||
#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
|
||||
defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
|
||||
defined (CONFIG_ATIXL_BUSMOUSE)
|
||||
mem_start = mouse_init(mem_start);
|
||||
#endif
|
||||
#ifdef CONFIG_SOUND
|
||||
mem_start = soundcard_init(mem_start);
|
||||
#endif
|
||||
#if CONFIG_TAPE_QIC02
|
||||
mem_start = tape_qic02_init(mem_start);
|
||||
#endif
|
||||
/*
|
||||
* Rude way to allocate kernel memory buffer for tape device
|
||||
*/
|
||||
#ifdef CONFIG_FTAPE
|
||||
/* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
|
||||
ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
|
||||
printk( "ftape: allocated %d buffers alligned at: %p\n",
|
||||
NR_FTAPE_BUFFERS, ftape_big_buffer);
|
||||
mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
|
||||
#endif
|
||||
return mem_start;
|
||||
}
|
99
source/THIRDPARTY/linux-old/drivers/char/mouse.c
Normal file
99
source/THIRDPARTY/linux-old/drivers/char/mouse.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* linux/kernel/chr_drv/mouse.c
|
||||
*
|
||||
* Generic mouse open routine by Johan Myreen
|
||||
*
|
||||
* Based on code from Linus
|
||||
*
|
||||
* Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
|
||||
* changes incorporated into 0.97pl4
|
||||
* by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
|
||||
* See busmouse.c for particulars.
|
||||
*
|
||||
* Made things a lot mode modular - easy to compile in just one or two
|
||||
* of the mouse drivers, as they are now completely independent. Linus.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mouse.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
/*
|
||||
* note that you can remove any or all of the drivers by undefining
|
||||
* the minor values in <linux/mouse.h>
|
||||
*/
|
||||
extern struct file_operations bus_mouse_fops;
|
||||
extern struct file_operations psaux_fops;
|
||||
extern struct file_operations ms_bus_mouse_fops;
|
||||
extern struct file_operations atixl_busmouse_fops;
|
||||
|
||||
extern unsigned long bus_mouse_init(unsigned long);
|
||||
extern unsigned long psaux_init(unsigned long);
|
||||
extern unsigned long ms_bus_mouse_init(unsigned long);
|
||||
extern unsigned long atixl_busmouse_init(unsigned long);
|
||||
|
||||
static int mouse_open(struct inode * inode, struct file * file)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
|
||||
switch (minor) {
|
||||
#ifdef CONFIG_BUSMOUSE
|
||||
case BUSMOUSE_MINOR:
|
||||
file->f_op = &bus_mouse_fops;
|
||||
break;
|
||||
#endif
|
||||
#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
|
||||
case PSMOUSE_MINOR:
|
||||
file->f_op = &psaux_fops;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_MS_BUSMOUSE
|
||||
case MS_BUSMOUSE_MINOR:
|
||||
file->f_op = &ms_bus_mouse_fops;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_ATIXL_BUSMOUSE
|
||||
case ATIXL_BUSMOUSE_MINOR:
|
||||
file->f_op = &atixl_busmouse_fops;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
return file->f_op->open(inode,file);
|
||||
}
|
||||
|
||||
static struct file_operations mouse_fops = {
|
||||
NULL, /* seek */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* readdir */
|
||||
NULL, /* select */
|
||||
NULL, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
mouse_open,
|
||||
NULL /* release */
|
||||
};
|
||||
|
||||
unsigned long mouse_init(unsigned long kmem_start)
|
||||
{
|
||||
#ifdef CONFIG_BUSMOUSE
|
||||
kmem_start = bus_mouse_init(kmem_start);
|
||||
#endif
|
||||
#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
|
||||
kmem_start = psaux_init(kmem_start);
|
||||
#endif
|
||||
#ifdef CONFIG_MS_BUSMOUSE
|
||||
kmem_start = ms_bus_mouse_init(kmem_start);
|
||||
#endif
|
||||
#ifdef CONFIG_ATIXL_BUSMOUSE
|
||||
kmem_start = atixl_busmouse_init(kmem_start);
|
||||
#endif
|
||||
if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops))
|
||||
printk("unable to get major %d for mouse devices\n",
|
||||
MOUSE_MAJOR);
|
||||
return kmem_start;
|
||||
}
|
175
source/THIRDPARTY/linux-old/drivers/char/msbusmouse.c
Normal file
175
source/THIRDPARTY/linux-old/drivers/char/msbusmouse.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Microsoft busmouse driver based on Logitech driver (see busmouse.c)
|
||||
*
|
||||
* Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
|
||||
*
|
||||
* Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
|
||||
* 8/28/92
|
||||
*
|
||||
* Microsoft Bus Mouse support folded into 0.97pl4 code
|
||||
* by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
|
||||
* Changes: Logitech and Microsoft support in the same kernel.
|
||||
* Defined new constants in busmouse.h for MS mice.
|
||||
* Added int mse_busmouse_type to distinguish busmouse types
|
||||
* Added a couple of new functions to handle differences in using
|
||||
* MS vs. Logitech (where the int variable wasn't appropriate).
|
||||
*
|
||||
* Modified by Peter Cervasio (address above) (26SEP92)
|
||||
* Changes: Included code to (properly?) detect when a Microsoft mouse is
|
||||
* really attached to the machine. Don't know what this does to
|
||||
* Logitech bus mice, but all it does is read ports.
|
||||
*
|
||||
* Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de)
|
||||
* Changes: Better interrupt-handler (like in busmouse.c).
|
||||
* Some changes to reduce code-size.
|
||||
* Changed dectection code to use inb_p() instead of doing empty
|
||||
* loops to delay i/o.
|
||||
*
|
||||
* version 0.3a
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/busmouse.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
static struct mouse_status mouse;
|
||||
|
||||
static void ms_mouse_interrupt(int unused)
|
||||
{
|
||||
char dx, dy;
|
||||
unsigned char buttons;
|
||||
|
||||
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
|
||||
outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT);
|
||||
|
||||
outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT);
|
||||
dx = inb(MS_MSE_DATA_PORT);
|
||||
|
||||
outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT);
|
||||
dy = inb(MS_MSE_DATA_PORT);
|
||||
|
||||
outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT);
|
||||
buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07;
|
||||
|
||||
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
|
||||
outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
|
||||
|
||||
if (dx != 0 || dy != 0 || buttons != mouse.buttons || ((~buttons) & 0x07)) {
|
||||
mouse.buttons = buttons;
|
||||
mouse.dx += dx;
|
||||
mouse.dy += dy;
|
||||
mouse.ready = 1;
|
||||
wake_up_interruptible(&mouse.wait);
|
||||
}
|
||||
}
|
||||
|
||||
static void release_mouse(struct inode * inode, struct file * file)
|
||||
{
|
||||
MS_MSE_INT_OFF();
|
||||
mouse.active = mouse.ready = 0;
|
||||
free_irq(MOUSE_IRQ);
|
||||
}
|
||||
|
||||
static int open_mouse(struct inode * inode, struct file * file)
|
||||
{
|
||||
if (!mouse.present)
|
||||
return -EINVAL;
|
||||
if (mouse.active)
|
||||
return -EBUSY;
|
||||
mouse.active = 1;
|
||||
mouse.ready = mouse.dx = mouse.dy = 0;
|
||||
mouse.buttons = 0x80;
|
||||
if (request_irq(MOUSE_IRQ, ms_mouse_interrupt)) {
|
||||
mouse.active = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
|
||||
MS_MSE_INT_ON();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
int i, dx, dy;
|
||||
|
||||
if (count < 3)
|
||||
return -EINVAL;
|
||||
if (!mouse.ready)
|
||||
return -EAGAIN;
|
||||
put_fs_byte(mouse.buttons | 0x80, buffer);
|
||||
dx = mouse.dx < -127 ? -127 : mouse.dx > 127 ? 127 : mouse.dx;
|
||||
dy = mouse.dy < -127 ? 127 : mouse.dy > 127 ? -127 : -mouse.dy;
|
||||
put_fs_byte((char)dx, buffer + 1);
|
||||
put_fs_byte((char)dy, buffer + 2);
|
||||
for (i = 3; i < count; i++)
|
||||
put_fs_byte(0x00, buffer + i);
|
||||
mouse.dx -= dx;
|
||||
mouse.dy += dy;
|
||||
mouse.ready = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||||
{
|
||||
if (sel_type != SEL_IN)
|
||||
return 0;
|
||||
if (mouse.ready)
|
||||
return 1;
|
||||
select_wait(&mouse.wait,wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct file_operations ms_bus_mouse_fops = {
|
||||
NULL, /* mouse_seek */
|
||||
read_mouse,
|
||||
write_mouse,
|
||||
NULL, /* mouse_readdir */
|
||||
mouse_select, /* mouse_select */
|
||||
NULL, /* mouse_ioctl */
|
||||
NULL, /* mouse_mmap */
|
||||
open_mouse,
|
||||
release_mouse,
|
||||
};
|
||||
|
||||
unsigned long ms_bus_mouse_init(unsigned long kmem_start)
|
||||
{
|
||||
int mse_byte, i;
|
||||
|
||||
mouse.present = mouse.active = mouse.ready = 0;
|
||||
mouse.buttons = 0x80;
|
||||
mouse.dx = mouse.dy = 0;
|
||||
mouse.wait = NULL;
|
||||
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
|
||||
|
||||
mse_byte = inb_p(MS_MSE_SIGNATURE_PORT);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
|
||||
if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
|
||||
mouse.present = 1;
|
||||
else
|
||||
mouse.present = 0;
|
||||
} else
|
||||
mouse.present = 0;
|
||||
}
|
||||
}
|
||||
if (mouse.present == 0) {
|
||||
return kmem_start;
|
||||
}
|
||||
MS_MSE_INT_OFF();
|
||||
printk("Microsoft BusMouse detected and installed.\n");
|
||||
return kmem_start;
|
||||
}
|
552
source/THIRDPARTY/linux-old/drivers/char/psaux.c
Normal file
552
source/THIRDPARTY/linux-old/drivers/char/psaux.c
Normal file
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
* linux/kernel/chr_drv/psaux.c
|
||||
*
|
||||
* Driver for PS/2 type mouse by Johan Myreen.
|
||||
*
|
||||
* Supports pointing devices attached to a PS/2 type
|
||||
* Keyboard and Auxiliary Device Controller.
|
||||
*
|
||||
* Corrections in device setup for some laptop mice & trackballs.
|
||||
* 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
|
||||
*
|
||||
* Changed to prevent keyboard lockups on AST Power Exec.
|
||||
* 28Jul93 Brad Bosch - brad@lachman.com
|
||||
*
|
||||
* Modified by Johan Myreen (jem@cs.hut.fi) 04Aug93
|
||||
* to include support for QuickPort mouse.
|
||||
*
|
||||
* Changed references to "QuickPort" with "82C710" since "QuickPort"
|
||||
* is not what this driver is all about -- QuickPort is just a
|
||||
* connector type, and this driver is for the mouse port on the Chips
|
||||
* & Technologies 82C710 interface chip. 15Nov93 jem@cs.hut.fi
|
||||
*/
|
||||
|
||||
/* Uncomment the following line if your mouse needs initialization. */
|
||||
|
||||
/* #define INITIALIZE_DEVICE */
|
||||
|
||||
#include <linux/timer.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
/* aux controller ports */
|
||||
#define AUX_INPUT_PORT 0x60 /* Aux device output buffer */
|
||||
#define AUX_OUTPUT_PORT 0x60 /* Aux device input buffer */
|
||||
#define AUX_COMMAND 0x64 /* Aux device command buffer */
|
||||
#define AUX_STATUS 0x64 /* Aux device status reg */
|
||||
|
||||
/* aux controller status bits */
|
||||
#define AUX_OBUF_FULL 0x21 /* output buffer (from device) full */
|
||||
#define AUX_IBUF_FULL 0x02 /* input buffer (to device) full */
|
||||
|
||||
/* aux controller commands */
|
||||
#define AUX_CMD_WRITE 0x60 /* value to write to controller */
|
||||
#define AUX_MAGIC_WRITE 0xd4 /* value to send aux device data */
|
||||
|
||||
#define AUX_INTS_ON 0x47 /* enable controller interrupts */
|
||||
#define AUX_INTS_OFF 0x65 /* disable controller interrupts */
|
||||
|
||||
#define AUX_DISABLE 0xa7 /* disable aux */
|
||||
#define AUX_ENABLE 0xa8 /* enable aux */
|
||||
|
||||
/* aux device commands */
|
||||
#define AUX_SET_RES 0xe8 /* set resolution */
|
||||
#define AUX_SET_SCALE11 0xe6 /* set 1:1 scaling */
|
||||
#define AUX_SET_SCALE21 0xe7 /* set 2:1 scaling */
|
||||
#define AUX_GET_SCALE 0xe9 /* get scaling factor */
|
||||
#define AUX_SET_STREAM 0xea /* set stream mode */
|
||||
#define AUX_SET_SAMPLE 0xf3 /* set sample rate */
|
||||
#define AUX_ENABLE_DEV 0xf4 /* enable aux device */
|
||||
#define AUX_DISABLE_DEV 0xf5 /* disable aux device */
|
||||
#define AUX_RESET 0xff /* reset aux device */
|
||||
|
||||
#define MAX_RETRIES 60 /* some aux operations take long time*/
|
||||
#define AUX_IRQ 12
|
||||
#define AUX_BUF_SIZE 2048
|
||||
|
||||
/* 82C710 definitions */
|
||||
|
||||
#define QP_DATA 0x310 /* Data Port I/O Address */
|
||||
#define QP_STATUS 0x311 /* Status Port I/O Address */
|
||||
|
||||
#define QP_DEV_IDLE 0x01 /* Device Idle */
|
||||
#define QP_RX_FULL 0x02 /* Device Char received */
|
||||
#define QP_TX_IDLE 0x04 /* Device XMIT Idle */
|
||||
#define QP_RESET 0x08 /* Device Reset */
|
||||
#define QP_INTS_ON 0x10 /* Device Interrupt On */
|
||||
#define QP_ERROR_FLAG 0x20 /* Device Error */
|
||||
#define QP_CLEAR 0x40 /* Device Clear */
|
||||
#define QP_ENABLE 0x80 /* Device Enable */
|
||||
|
||||
#define QP_IRQ 12
|
||||
|
||||
extern unsigned char aux_device_present;
|
||||
extern unsigned char kbd_read_mask; /* from keyboard.c */
|
||||
|
||||
struct aux_queue {
|
||||
unsigned long head;
|
||||
unsigned long tail;
|
||||
struct wait_queue *proc_list;
|
||||
unsigned char buf[AUX_BUF_SIZE];
|
||||
};
|
||||
|
||||
static struct aux_queue *queue;
|
||||
static int aux_ready = 0;
|
||||
static int aux_busy = 0;
|
||||
static int aux_present = 0;
|
||||
static int poll_aux_status(void);
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
static int qp_present = 0;
|
||||
static int qp_busy = 0;
|
||||
static int qp_data = QP_DATA;
|
||||
static int qp_status = QP_STATUS;
|
||||
|
||||
static int poll_qp_status(void);
|
||||
static int probe_qp(void);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Write to aux device
|
||||
*/
|
||||
|
||||
static void aux_write_dev(int val)
|
||||
{
|
||||
poll_aux_status();
|
||||
outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); /* write magic cookie */
|
||||
poll_aux_status();
|
||||
outb_p(val,AUX_OUTPUT_PORT); /* write data */
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to device & handle returned ack
|
||||
*/
|
||||
|
||||
#if defined INITIALIZE_DEVICE
|
||||
static int aux_write_ack(int val)
|
||||
{
|
||||
int retries = 0;
|
||||
|
||||
aux_write_dev(val); /* write the value to the device */
|
||||
while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL
|
||||
&& retries < MAX_RETRIES) { /* wait for ack */
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + 5;
|
||||
schedule();
|
||||
retries++;
|
||||
}
|
||||
|
||||
if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
|
||||
{
|
||||
return (inb(AUX_INPUT_PORT));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* INITIALIZE_DEVICE */
|
||||
|
||||
/*
|
||||
* Write aux device command
|
||||
*/
|
||||
|
||||
static void aux_write_cmd(int val)
|
||||
{
|
||||
poll_aux_status();
|
||||
outb_p(AUX_CMD_WRITE,AUX_COMMAND);
|
||||
poll_aux_status();
|
||||
outb_p(val,AUX_OUTPUT_PORT);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int get_from_queue(void)
|
||||
{
|
||||
unsigned int result;
|
||||
unsigned long flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
result = queue->buf[queue->tail];
|
||||
queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
|
||||
restore_flags(flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static inline int queue_empty(void)
|
||||
{
|
||||
return queue->head == queue->tail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Interrupt from the auxiliary device: a character
|
||||
* is waiting in the keyboard/aux controller.
|
||||
*/
|
||||
|
||||
static void aux_interrupt(int cpl)
|
||||
{
|
||||
int head = queue->head;
|
||||
int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
|
||||
|
||||
queue->buf[head] = inb(AUX_INPUT_PORT);
|
||||
if (head != maxhead) {
|
||||
head++;
|
||||
head &= AUX_BUF_SIZE-1;
|
||||
}
|
||||
queue->head = head;
|
||||
aux_ready = 1;
|
||||
wake_up_interruptible(&queue->proc_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt handler for the 82C710 mouse port. A character
|
||||
* is waiting in the 82C710.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
static void qp_interrupt(int cpl)
|
||||
{
|
||||
int head = queue->head;
|
||||
int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
|
||||
|
||||
queue->buf[head] = inb(qp_data);
|
||||
if (head != maxhead) {
|
||||
head++;
|
||||
head &= AUX_BUF_SIZE-1;
|
||||
}
|
||||
queue->head = head;
|
||||
aux_ready = 1;
|
||||
wake_up_interruptible(&queue->proc_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void release_aux(struct inode * inode, struct file * file)
|
||||
{
|
||||
aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */
|
||||
aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
|
||||
poll_aux_status();
|
||||
outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
|
||||
poll_aux_status();
|
||||
free_irq(AUX_IRQ);
|
||||
aux_busy = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
static void release_qp(struct inode * inode, struct file * file)
|
||||
{
|
||||
unsigned char status;
|
||||
|
||||
if (!poll_qp_status())
|
||||
printk("Warning: Mouse device busy in release_qp()\n");
|
||||
status = inb_p(qp_status);
|
||||
outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
|
||||
if (!poll_qp_status())
|
||||
printk("Warning: Mouse device busy in release_qp()\n");
|
||||
free_irq(QP_IRQ);
|
||||
qp_busy = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Install interrupt handler.
|
||||
* Enable auxiliary device.
|
||||
*/
|
||||
|
||||
static int open_aux(struct inode * inode, struct file * file)
|
||||
{
|
||||
if (!aux_present)
|
||||
return -EINVAL;
|
||||
if (aux_busy)
|
||||
return -EBUSY;
|
||||
if (!poll_aux_status())
|
||||
return -EBUSY;
|
||||
aux_busy = 1;
|
||||
queue->head = queue->tail = 0; /* Flush input queue */
|
||||
if (request_irq(AUX_IRQ, aux_interrupt)) {
|
||||
aux_busy = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
poll_aux_status();
|
||||
outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */
|
||||
aux_write_dev(AUX_ENABLE_DEV); /* enable aux device */
|
||||
aux_write_cmd(AUX_INTS_ON); /* enable controller ints */
|
||||
poll_aux_status();
|
||||
aux_ready = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
/*
|
||||
* Install interrupt handler.
|
||||
* Enable the device, enable interrupts. Set qp_busy
|
||||
* (allow only one opener at a time.)
|
||||
*/
|
||||
|
||||
static int open_qp(struct inode * inode, struct file * file)
|
||||
{
|
||||
unsigned char status;
|
||||
|
||||
if (!qp_present)
|
||||
return -EINVAL;
|
||||
|
||||
if (qp_busy)
|
||||
return -EBUSY;
|
||||
|
||||
if (request_irq(QP_IRQ, qp_interrupt))
|
||||
return -EBUSY;
|
||||
|
||||
qp_busy = 1;
|
||||
|
||||
status = inb_p(qp_status);
|
||||
status |= (QP_ENABLE|QP_RESET);
|
||||
outb_p(status, qp_status);
|
||||
status &= ~(QP_RESET);
|
||||
outb_p(status, qp_status);
|
||||
|
||||
queue->head = queue->tail = 0; /* Flush input queue */
|
||||
status |= QP_INTS_ON;
|
||||
outb_p(status, qp_status); /* Enable interrupts */
|
||||
|
||||
while (!poll_qp_status()) {
|
||||
printk("Error: Mouse device busy in open_qp()\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Write to the aux device.
|
||||
*/
|
||||
|
||||
static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
int i = count;
|
||||
|
||||
while (i--) {
|
||||
if (!poll_aux_status())
|
||||
return -EIO;
|
||||
outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
|
||||
if (!poll_aux_status())
|
||||
return -EIO;
|
||||
outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
|
||||
}
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
/*
|
||||
* Write to the 82C710 mouse device.
|
||||
*/
|
||||
|
||||
static int write_qp(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
int i = count;
|
||||
|
||||
while (i--) {
|
||||
if (!poll_qp_status())
|
||||
return -EIO;
|
||||
outb_p(get_fs_byte(buffer++), qp_data);
|
||||
}
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Put bytes from input queue to buffer.
|
||||
*/
|
||||
|
||||
static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
|
||||
{
|
||||
struct wait_queue wait = { current, NULL };
|
||||
int i = count;
|
||||
unsigned char c;
|
||||
|
||||
if (queue_empty()) {
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
add_wait_queue(&queue->proc_list, &wait);
|
||||
repeat:
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
if (queue_empty() && !(current->signal & ~current->blocked)) {
|
||||
schedule();
|
||||
goto repeat;
|
||||
}
|
||||
current->state = TASK_RUNNING;
|
||||
remove_wait_queue(&queue->proc_list, &wait);
|
||||
}
|
||||
while (i > 0 && !queue_empty()) {
|
||||
c = get_from_queue();
|
||||
put_fs_byte(c, buffer++);
|
||||
i--;
|
||||
}
|
||||
aux_ready = !queue_empty();
|
||||
if (count-i) {
|
||||
inode->i_atime = CURRENT_TIME;
|
||||
return count-i;
|
||||
}
|
||||
if (current->signal & ~current->blocked)
|
||||
return -ERESTARTSYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||||
{
|
||||
if (sel_type != SEL_IN)
|
||||
return 0;
|
||||
if (aux_ready)
|
||||
return 1;
|
||||
select_wait(&queue->proc_list, wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct file_operations psaux_fops = {
|
||||
NULL, /* seek */
|
||||
read_aux,
|
||||
write_aux,
|
||||
NULL, /* readdir */
|
||||
aux_select,
|
||||
NULL, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
open_aux,
|
||||
release_aux,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Initialize driver. First check for a 82C710 chip; if found
|
||||
* forget about the Aux port and use the *_qp functions.
|
||||
*/
|
||||
|
||||
unsigned long psaux_init(unsigned long kmem_start)
|
||||
{
|
||||
int qp_found = 0;
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
printk("Probing 82C710 mouse port device.\n");
|
||||
if ((qp_found = probe_qp())) {
|
||||
printk("82C710 type pointing device detected -- driver installed.\n");
|
||||
/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
|
||||
qp_present = 1;
|
||||
psaux_fops.write = write_qp;
|
||||
psaux_fops.open = open_qp;
|
||||
psaux_fops.release = release_qp;
|
||||
poll_qp_status();
|
||||
} else
|
||||
#endif
|
||||
if (aux_device_present == 0xaa) {
|
||||
printk("PS/2 auxiliary pointing device detected -- driver installed.\n");
|
||||
aux_present = 1;
|
||||
kbd_read_mask = AUX_OBUF_FULL;
|
||||
poll_aux_status();
|
||||
} else {
|
||||
return kmem_start; /* No mouse at all */
|
||||
}
|
||||
queue = (struct aux_queue *) kmem_start;
|
||||
kmem_start += sizeof (struct aux_queue);
|
||||
queue->head = queue->tail = 0;
|
||||
queue->proc_list = NULL;
|
||||
if (!qp_found) {
|
||||
#if defined INITIALIZE_DEVICE
|
||||
outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */
|
||||
aux_write_ack(AUX_SET_SAMPLE);
|
||||
aux_write_ack(100); /* 100 samples/sec */
|
||||
aux_write_ack(AUX_SET_RES);
|
||||
aux_write_ack(3); /* 8 counts per mm */
|
||||
aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
|
||||
poll_aux_status();
|
||||
#endif /* INITIALIZE_DEVICE */
|
||||
outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
|
||||
aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
|
||||
poll_aux_status();
|
||||
}
|
||||
return kmem_start;
|
||||
}
|
||||
|
||||
static int poll_aux_status(void)
|
||||
{
|
||||
int retries=0;
|
||||
|
||||
while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
|
||||
if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)
|
||||
inb_p(AUX_INPUT_PORT);
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + 5;
|
||||
schedule();
|
||||
retries++;
|
||||
}
|
||||
return !(retries==MAX_RETRIES);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_82C710_MOUSE
|
||||
/*
|
||||
* Wait for device to send output char and flush any input char.
|
||||
*/
|
||||
|
||||
static int poll_qp_status(void)
|
||||
{
|
||||
int retries=0;
|
||||
|
||||
while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
|
||||
!= (QP_DEV_IDLE|QP_TX_IDLE)
|
||||
&& retries < MAX_RETRIES) {
|
||||
|
||||
if (inb_p(qp_status)&(QP_RX_FULL))
|
||||
inb_p(qp_data);
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
current->timeout = jiffies + 5;
|
||||
schedule();
|
||||
retries++;
|
||||
}
|
||||
return !(retries==MAX_RETRIES);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to read register in 82C710.
|
||||
*/
|
||||
|
||||
static inline unsigned char read_710(unsigned char index)
|
||||
{
|
||||
outb_p(index, 0x390); /* Write index */
|
||||
return inb_p(0x391); /* Read the data */
|
||||
}
|
||||
|
||||
/*
|
||||
* See if we can find a 82C710 device. Read mouse address.
|
||||
*/
|
||||
|
||||
static int probe_qp(void)
|
||||
{
|
||||
outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
|
||||
outb_p(0xaa, 0x3fa); /* Inverse of 55 */
|
||||
outb_p(0x36, 0x3fa); /* Address the chip */
|
||||
outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
|
||||
outb_p(0x1b, 0x2fa); /* Inverse of e4 */
|
||||
if (read_710(0x0f) != 0xe4) /* Config address found? */
|
||||
return 0; /* No: no 82C710 here */
|
||||
qp_data = read_710(0x0d)*4; /* Get mouse I/O address */
|
||||
qp_status = qp_data+1;
|
||||
outb_p(0x0f, 0x390);
|
||||
outb_p(0x0f, 0x391); /* Close config mode */
|
||||
return 1;
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue