remove unmaintained bitsy (ipaq) kernel
This commit is contained in:
parent
8d9a94a66e
commit
76e4f7caf9
|
@ -1,245 +0,0 @@
|
|||
|
||||
|
||||
The bitsy comes with Wince. To get to Plan 9, you will need a serial cable,
|
||||
a Windows machine with a serial interface, the CDROM that comes with the bitsy,
|
||||
and a Plan 9 machine with a serial interface. The Windows machine is used to
|
||||
get the Linux boot loader onto the bitsy (and to save away wince, if you so
|
||||
desire). The Plan 9 machine is used to get the plan 9 kernel and a read only
|
||||
file system onto the bitsy.
|
||||
|
||||
0. charge up the bitsy.
|
||||
|
||||
1. go to
|
||||
ftp://ftp.handhelds.org/pub/linux/compaq/ipaq/stable/install.html
|
||||
Get the latest version of the Linux "osloader" and "bootldr" programs
|
||||
(we have tried versions 1.3.0 and 0000-2.14.8, respectively; newest
|
||||
versions seem not to allow you to suspend your bitsy due to a bug
|
||||
which is probably ours). You can find them all at
|
||||
www.collyer.net/who/geoff/9/bitsy/.
|
||||
|
||||
2. Use ActiveSync to copy osloader and bootldr to the bitsy. Copy or
|
||||
rename the bootldr binary to "bootldr" on Windows, then copy it to the
|
||||
bitsy; trying to rename it on WinCE won't produce the right result.
|
||||
|
||||
Steps 3 - 7 may work on a Pocket PC bitsy, but see Steps 3a - 7a
|
||||
if they don't or if you have a Pocket PC 2002 bitsy.
|
||||
|
||||
3. Run osloader by clicking on it under the WinCE File Explorer
|
||||
|
||||
4. Use osloader to save your WinCE flash away. This takes a while,
|
||||
as it's 16MB over a 115,200 baud line.
|
||||
|
||||
5. Select "Run" from the osloader menu. Ignore "Run from RAM"; it's
|
||||
not needed.
|
||||
|
||||
6. At this point, the bitsy's screen turns blank, but you can still
|
||||
talk to the bitsy over its serial port. The serial port is connected
|
||||
to the OS loader's terminal program. On Windows, you have to exit
|
||||
ActiveSync before the serial port is available for a terminal program.
|
||||
I moved the bitsy and its cable over to a Plan 9 machine and connected
|
||||
using "con -b 115200 /dev/eia[01]" to talk to the console. The
|
||||
command "help" lists the OS loader's commands.
|
||||
|
||||
7. Now you need to download the BOOT loader program into flash (right
|
||||
now, you're only running the OS loader program out of RAM; rebooting
|
||||
will get you back to WinCE). In the con window, "load bootldr" to the
|
||||
bitsy. It will indicate that it's starting an xmodem download.
|
||||
Under con, type "Ctrl-\" to get a ">>>" prompt. At this prompt, you
|
||||
want to run Plan 9's xms program to pipe the bootldr program to the
|
||||
bitsy. For example, to download /tmp/bootldr, type "!xms /tmp/bootldr".
|
||||
|
||||
If this step works successfully, the OS loader will print out some sort
|
||||
of OK checksum message.
|
||||
|
||||
If you have a Pocket PC 2002 or steps 3 - 7 above didn't work for you,
|
||||
try 3a - 7a.
|
||||
|
||||
3a. Copy BootBlaster (also) to the bitsy via ActiveSync.
|
||||
|
||||
4a. Save your flash by running osloader and selecting "Flash->Save to
|
||||
File". As it produces 4MB files, use ActiveSync to copy them off the
|
||||
bitsy.
|
||||
|
||||
5a. Move the bitsy and its cable over to a Plan 9 machine and connect
|
||||
using "con -b 115200 /dev/eia[01]" to talk to the console.
|
||||
|
||||
6a. Run BootBlaster by clicking on it under the WinCE File Explorer.
|
||||
|
||||
7a. Select "Program"; it should copy "bootldr" into your flash in
|
||||
about 15 seconds.
|
||||
|
||||
8. Reboot your bitsy (either cycle the power or use the reset
|
||||
switch). The new boot loader runs out of Flash. You'll get the linux
|
||||
penguin splash screen and a bunch of options triggered by buttons.
|
||||
Pick the one that gets you to the boot loader.
|
||||
|
||||
9. Make the partitions you need in the bitsy's flash, type, using
|
||||
the con program:
|
||||
partition reset
|
||||
partition define bootldr 0x000000 0x040000 2
|
||||
partition define params 0x040000 0x040000 0
|
||||
partition define kernel 0x080000 0x0c0000 0
|
||||
partition define user 0x140000 0x0c0000 0
|
||||
partition define ramdisk 0x200000 0x600000 0
|
||||
partition define fs 0x800000 0x800000 0
|
||||
params save
|
||||
|
||||
These are the partitions as shown by partition show:
|
||||
boot> partition show
|
||||
argv[1]=partition
|
||||
npartitions=00000006
|
||||
bootldr
|
||||
base: 00000000
|
||||
size: 00040000
|
||||
flags: 00000002
|
||||
params
|
||||
base: 00040000
|
||||
size: 00040000
|
||||
flags: 00000000
|
||||
kernel
|
||||
base: 00080000
|
||||
size: 000C0000
|
||||
flags: 00000000
|
||||
user
|
||||
base: 00140000
|
||||
size: 000C0000
|
||||
flags: 00000000
|
||||
ramdisk
|
||||
base: 00200000
|
||||
size: 00600000
|
||||
flags: 00000000
|
||||
fs
|
||||
base: 00800000
|
||||
size: 00800000
|
||||
flags: 00000000
|
||||
|
||||
After each line you'll get a message like `defining partition: params'.
|
||||
Different versions of the bootloader predefine different partitions.
|
||||
The bootldr partition is usually predefined, so you don't have to remake
|
||||
that. You may have to delete one or two partitions. The command is
|
||||
partition delete <name>
|
||||
Make sure the partition layout is as given above; some of this knowledge is
|
||||
built into the kernel.
|
||||
|
||||
10. Before you can fill the new partitions with a kernel and a read-only
|
||||
file system, you'll have to make them. In the directory /sys/src/9/bitsy,
|
||||
type mk and mk paqdisk. Before mk-ing paqdisk, make sure you have all
|
||||
the necessary arm binaries installed in /arm and examine the file
|
||||
paqfiles/mfs to see what you need to change for connecting to your local
|
||||
file servers.
|
||||
|
||||
11. Now you can type "load kernel". The boot loader will prompt for
|
||||
another xmodem download. Again escape using "Ctrl-\", then use
|
||||
"!xms /sys/src/9/bitsy/9bitsy" (or "!xms /arm/9bitsy" if you've already
|
||||
installed it).
|
||||
|
||||
12. Download the ramdisk, using "load ramdisk" and
|
||||
"!xms /sys/src/9/bitsy/paqdisk" (or "!xms /arm/paqdisk" if you've already
|
||||
installed it), similarly to 10, above.
|
||||
|
||||
13. Type `boot' or `boot flash' depending on your version of the boot loader.
|
||||
If you need the latter, you may want to
|
||||
|
||||
set boot_type flash
|
||||
params save
|
||||
|
||||
to make boot flash the default.
|
||||
|
||||
You'll get a Dutch flag (or a French one, if you hold the iPaq the wrong way),
|
||||
then the boot screen will say, on the serial port, thus in your con window:
|
||||
|
||||
root is from [paq]:
|
||||
|
||||
Just wait a while or hit enter in the con window and it'll continue.
|
||||
|
||||
14. The bitsy will now want to calibrate the screen. It'll put up a
|
||||
series of crosses that you should press the center of. Hold the pen
|
||||
down over each cross for a second or so; aim carefully. Hold the
|
||||
machine in your hand the way you'ld normally use it or the calibration
|
||||
could be off since there is depth to the glass in the screen.
|
||||
|
||||
15. You'll get a new screen with a single line at the top and a
|
||||
keyboard/scribble area at the bottom. This is a simple one file
|
||||
editor. This file is similar to plan9.ini on PC's. There may be
|
||||
garbage on the top line. If there is, delete the garbage letters.
|
||||
(Be careful here: the backspace and delete keys are adjacent on the
|
||||
wee keyboard and it's much too easy to hit delete instead of
|
||||
backspace, especially if you haven't calibrated the screen dead-on.)
|
||||
You should be left with a single line containing (with different
|
||||
numbers):
|
||||
calibrate='-16374 22919 251 -24'
|
||||
You need to enter a few more things, including, but not limited to:
|
||||
|
||||
user=<user-name>
|
||||
wvkey1=<key string>
|
||||
wvkey2=<key string>
|
||||
wvkey3=<key string>
|
||||
wvtxkey=<key string>
|
||||
wvessid=<wavelan name>
|
||||
auth=<ip address>
|
||||
cpu=<ip address>
|
||||
proxy=<ip address>
|
||||
fs=<ip address>
|
||||
|
||||
Your best bet is to copy these off a working bitsy. wv*key* only
|
||||
matter if your wireless network is encrypted. When roaming the world,
|
||||
omit wv*. When you're done, hit the "ESC" key on the simulated
|
||||
keyboard, or the side button near the word iPAQ on the bitsy. The
|
||||
system will now come up as you. However, you'll get a message about
|
||||
the flash file system being corrupted, because we haven't yet
|
||||
initialized it.
|
||||
|
||||
16. To set up the file systems, sweep a window and give the following
|
||||
sequence of commands.
|
||||
|
||||
# aux/mkflashfs /dev/flash/fs
|
||||
# aux/flashfs
|
||||
|
||||
aux/flashfs created a Plan 9 server in /srv/brzr, which we can use to set up
|
||||
default directories.
|
||||
|
||||
# mount -c /srv/brzr /n/brzr
|
||||
# cd /n/brzr
|
||||
# mkdir n usr
|
||||
# mkdir n/fs n/emelie n/choline n/nslocum
|
||||
# mkdir usr/yourname usr/yourfriend
|
||||
|
||||
17. For safety, reboot the system:
|
||||
|
||||
# reboot
|
||||
|
||||
18. Now reboot, go through the Linux splash screen, the Plan 9 boot
|
||||
editor, and sweep yourself a new rio window.
|
||||
|
||||
Before you can connect to other machines, you need a way to enter
|
||||
passwords and keys into factotum. The easiest way to do this is to
|
||||
run
|
||||
|
||||
# auth/fgui &
|
||||
|
||||
in the window you just made. The window will disappear (fgui spends
|
||||
most of its time hidden), so sweep a new window and run the command
|
||||
|
||||
# mfs
|
||||
|
||||
to connect to file servers. You will probably need to modify mfs to
|
||||
work in your environment (see point 10), though you can supply many
|
||||
of the variables it needs in step 15, and doing
|
||||
|
||||
# import $cpu /net
|
||||
|
||||
before running mfs can go a long ways.
|
||||
|
||||
19. When you're all set with a working wavelan, you can download new
|
||||
kernels more quickly using
|
||||
|
||||
# bitsyload k
|
||||
|
||||
and new paqdisks using
|
||||
|
||||
# bitsyload r
|
||||
|
||||
(r stands for ramdisk, the name of the partition into which paqdisk goes).
|
||||
Note that overwriting the ramdisk partition will cause the read-only file
|
||||
system which forms the root of you namespace to fail. You'll need to
|
||||
reboot immediately after bytsyload r.
|
|
@ -1,49 +0,0 @@
|
|||
dev
|
||||
root
|
||||
cons
|
||||
dup
|
||||
env
|
||||
ether netif
|
||||
flash
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
|
||||
kprof
|
||||
mnt
|
||||
µc
|
||||
pcmcia cis
|
||||
draw
|
||||
penmouse
|
||||
pipe
|
||||
proc
|
||||
cap
|
||||
srv
|
||||
ssl
|
||||
uart
|
||||
uda1341
|
||||
sd
|
||||
|
||||
ip
|
||||
tcp
|
||||
udp
|
||||
ipifc
|
||||
icmp
|
||||
icmp6
|
||||
gre
|
||||
ipmux
|
||||
|
||||
link
|
||||
etherwavelan wavelan
|
||||
ethermedium
|
||||
|
||||
misc
|
||||
uartsa1110
|
||||
sdata
|
||||
|
||||
port
|
||||
int cpuserver = 1;
|
||||
|
||||
bootdir
|
||||
/$objtype/bin/paqfs
|
||||
/$objtype/bin/auth/factotum
|
||||
bootfs.paq
|
||||
boot
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
#include "mem.h"
|
||||
|
||||
// Bitsy development board uses two banks: KM416S4030C,
|
||||
// 12 row address bits, 8 col address bits
|
||||
// Bitsy uses two banks KM416S8030C, 12 row address bits,
|
||||
// 9 col address bits
|
||||
// Have to set DRAC0 to 14 row bits or else you only get 8 col bits
|
||||
// from the formfactor unit configuration registers: 0xF3536257
|
||||
mdcnfg: // DRAM Configuration Register 10.2.1
|
||||
WORD 1<<0 | 1<<2 | 0<<3 | 0x5<<4 | 0x3<<8 | 3<<12 | 3<<14
|
||||
mdrefr0: // DRAM Refresh Control Register 10.2.2
|
||||
WORD 1<<0 | 0x200<<4 | 1<<21 | 1<<22 | 1 <<31
|
||||
mdrefr1: // DRAM Refresh Control Register 10.2.2
|
||||
WORD 1<<0 | 0x200<<4 | 1<<21 | 1<<22
|
||||
mdrefr2: // DRAM Refresh Control Register 10.2.2
|
||||
WORD 1<<0 | 0x200<<4 | 1<<20 | 1<<21 | 1<<22
|
||||
|
||||
/* MDCAS settings from [1] Table 10-3 (page 10-18) */
|
||||
waveform0:
|
||||
WORD 0xAAAAAAA7
|
||||
waveform1:
|
||||
WORD 0xAAAAAAAA
|
||||
waveform2:
|
||||
WORD 0xAAAAAAAA
|
||||
|
||||
delay: // delay without using memory
|
||||
mov $100, r1 // 200MHz: 100 × (2 instructions @ 5 ns) == 1 ms
|
||||
l1:
|
||||
sub $1, r1
|
||||
bgt l1
|
||||
sub $1, r0
|
||||
bgt delay
|
||||
ret
|
||||
|
||||
reset:
|
||||
mov $INTREGS+4, r0 // turn off interrupts
|
||||
mov $0, (r0)
|
||||
|
||||
// Is this necessary on wakeup?
|
||||
mov $POWERREGS+14, r0 // set clock speed to 191.7MHz
|
||||
mov $0xb, (r0)
|
||||
|
||||
// This is necessary on hard reset, but not on sleep reset
|
||||
mov $0x80, r0 // wait ±128 µs
|
||||
bl delay
|
||||
|
||||
/* check to see if we're operating out of DRAM */
|
||||
bic $0x000000ff, pc, r4
|
||||
bic $0x0000ff00, r4
|
||||
bic $0x00ff0000, r4
|
||||
cmp r4, $PHYSDRAM0
|
||||
beq dram
|
||||
|
||||
dramwakeup:
|
||||
|
||||
mov $POWERREGS+0x4, r1 // Clear DH in Power Manager Sleep Status Register
|
||||
bic $(1<<3), (r1) // DH == DRAM Hold
|
||||
// This releases nCAS/DQM and nRAS/nSDCS pins to make DRAM exit selfrefresh
|
||||
|
||||
/* Set up the DRAM in banks 0 and 1 [1] 10.3 */
|
||||
mov $MEMCONFREGS, r1
|
||||
|
||||
mov mdrefr0, r2 // Turn on K1RUN
|
||||
mov r2, 0x1c(r1)
|
||||
|
||||
mov mdrefr1, r2 // Turn off SLFRSH
|
||||
mov r2, 0x1c(r1)
|
||||
|
||||
mov mdrefr2, r2 // Turn on E1PIN
|
||||
mov r2, 0x1c(r1)
|
||||
|
||||
mov waveform0, r2
|
||||
mov r2, 0x4(r1)
|
||||
|
||||
mov waveform1, r2
|
||||
mov r2, 0x8(r1)
|
||||
|
||||
mov waveform2, r2
|
||||
mov r2, 0xc(r1)
|
||||
|
||||
mov $PHYSDRAM0, r0
|
||||
mov 0x00(r0), r2 // Eight non-burst read cycles
|
||||
mov 0x20(r0), r2
|
||||
mov 0x40(r0), r2
|
||||
mov 0x60(r0), r2
|
||||
mov 0x80(r0), r2
|
||||
mov 0xa0(r0), r2
|
||||
mov 0xc0(r0), r2
|
||||
mov 0xe0(r0), r2
|
||||
|
||||
mov mdcnfg, r2 // Enable memory banks
|
||||
mov r2, 0x0(r1)
|
||||
|
||||
// Is there any use in turning on EAPD and KAPD in the MDREFR register?
|
||||
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
dram:
|
||||
|
||||
|
|
@ -1,254 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
|
||||
enum {
|
||||
RTCREGS = 0x90010000, /* real time clock registers */
|
||||
RTSR_al = 0x01, /* alarm detected */
|
||||
RTSR_hz = 0x02, /* 1Hz tick */
|
||||
RTSR_ale= 0x04, /* alarm interrupt enable */
|
||||
RTSR_hze= 0x08, /* 1Hz tick enable */
|
||||
|
||||
Never = 0xffffffff,
|
||||
};
|
||||
|
||||
typedef struct OSTimer
|
||||
{
|
||||
ulong osmr[4]; /* match registers */
|
||||
volatile ulong oscr; /* counter register */
|
||||
ulong ossr; /* status register */
|
||||
ulong ower; /* watchdog enable register */
|
||||
ulong oier; /* timer interrupt enable register */
|
||||
} OSTimer;
|
||||
|
||||
typedef struct RTCregs
|
||||
{
|
||||
ulong rtar; /* alarm */
|
||||
ulong rcnr; /* count */
|
||||
ulong rttr; /* trim */
|
||||
ulong dummy; /* hole */
|
||||
ulong rtsr; /* status */
|
||||
} RTCregs;
|
||||
|
||||
OSTimer *timerregs = (OSTimer*)OSTIMERREGS;
|
||||
RTCregs *rtcregs = (RTCregs*)RTCREGS;
|
||||
static int clockinited;
|
||||
|
||||
static void clockintr(Ureg*, void*);
|
||||
static void rtcintr(Ureg*, void*);
|
||||
static Tval when; /* scheduled time of next interrupt */
|
||||
|
||||
long timeradjust;
|
||||
|
||||
enum
|
||||
{
|
||||
Minfreq = ClockFreq/HZ, /* At least one interrupt per HZ (50 ms) */
|
||||
Maxfreq = ClockFreq/10000, /* At most one interrupt every 100 µs */
|
||||
};
|
||||
|
||||
ulong
|
||||
clockpower(int on)
|
||||
{
|
||||
static ulong savedtime;
|
||||
|
||||
if (on){
|
||||
timerregs->ossr |= 1<<0;
|
||||
timerregs->oier = 1<<0;
|
||||
timerregs->osmr[0] = timerregs->oscr + Minfreq;
|
||||
if (rtcregs->rttr == 0){
|
||||
rtcregs->rttr = 0x8000; // nominal frequency.
|
||||
rtcregs->rcnr = 0;
|
||||
rtcregs->rtar = 0xffffffff;
|
||||
rtcregs->rtsr |= RTSR_ale;
|
||||
rtcregs->rtsr |= RTSR_hze;
|
||||
}
|
||||
if (rtcregs->rcnr > savedtime)
|
||||
return rtcregs->rcnr - savedtime;
|
||||
} else
|
||||
savedtime = rtcregs->rcnr;
|
||||
clockinited = on;
|
||||
return 0L;
|
||||
}
|
||||
|
||||
void
|
||||
clockinit(void)
|
||||
{
|
||||
ulong x;
|
||||
ulong id;
|
||||
|
||||
/* map the clock registers */
|
||||
timerregs = mapspecial(OSTIMERREGS, sizeof(OSTimer));
|
||||
rtcregs = mapspecial(RTCREGS, sizeof(RTCregs));
|
||||
|
||||
/* enable interrupts on match register 0, turn off all others */
|
||||
timerregs->ossr |= 1<<0;
|
||||
intrenable(IRQ, IRQtimer0, clockintr, nil, "clock");
|
||||
timerregs->oier = 1<<0;
|
||||
|
||||
/* figure out processor frequency */
|
||||
x = powerregs->ppcr & 0x1f;
|
||||
conf.hz = ClockFreq*(x*4+16);
|
||||
conf.mhz = (conf.hz+499999)/1000000;
|
||||
|
||||
/* get processor type */
|
||||
id = getcpuid();
|
||||
|
||||
print("%lud MHZ ARM, ver %lux/part %lux/step %lud\n", conf.mhz,
|
||||
(id>>16)&0xff, (id>>4)&0xfff, id&0xf);
|
||||
|
||||
/* post interrupt 1/HZ secs from now */
|
||||
when = timerregs->oscr + Minfreq;
|
||||
timerregs->osmr[0] = when;
|
||||
|
||||
/* enable RTC interrupts and alarms */
|
||||
intrenable(IRQ, IRQrtc, rtcintr, nil, "rtc");
|
||||
rtcregs->rttr = 0x8000; // make rcnr 1Hz
|
||||
rtcregs->rcnr = 0; // reset counter
|
||||
rtcregs->rtsr |= RTSR_al;
|
||||
rtcregs->rtsr |= RTSR_ale;
|
||||
|
||||
timersinit();
|
||||
|
||||
clockinited = 1;
|
||||
}
|
||||
|
||||
/* turn 32 bit counter into a 64 bit one. since todfix calls
|
||||
* us at least once a second and we overflow once every 1165
|
||||
* seconds, we won't miss an overflow.
|
||||
*/
|
||||
uvlong
|
||||
fastticks(uvlong *hz)
|
||||
{
|
||||
static uvlong high;
|
||||
static ulong last;
|
||||
ulong x;
|
||||
|
||||
if(hz != nil)
|
||||
*hz = ClockFreq;
|
||||
x = timerregs->oscr;
|
||||
if(x < last)
|
||||
high += 1LL<<32;
|
||||
last = x;
|
||||
return high+x;
|
||||
}
|
||||
|
||||
ulong
|
||||
µs(void)
|
||||
{
|
||||
return fastticks2us(fastticks(nil));
|
||||
}
|
||||
|
||||
void
|
||||
timerset(Tval v)
|
||||
{
|
||||
ulong next, tics; /* Must be unsigned! */
|
||||
static int count;
|
||||
|
||||
next = v;
|
||||
|
||||
/* post next interrupt: calculate # of tics from now */
|
||||
tics = next - timerregs->oscr - Maxfreq;
|
||||
if (tics > Minfreq){
|
||||
timeradjust++;
|
||||
next = timerregs->oscr + Maxfreq;
|
||||
}
|
||||
timerregs->osmr[0] = next;
|
||||
}
|
||||
|
||||
static void
|
||||
clockintr(Ureg *ureg, void*)
|
||||
{
|
||||
/* reset previous interrupt */
|
||||
timerregs->ossr |= 1<<0;
|
||||
when += Minfreq;
|
||||
timerregs->osmr[0] = when; /* insurance */
|
||||
|
||||
timerintr(ureg, when);
|
||||
}
|
||||
|
||||
void
|
||||
rtcalarm(ulong secs)
|
||||
{
|
||||
vlong t;
|
||||
|
||||
if (t == 0){
|
||||
iprint("RTC alarm cancelled\n");
|
||||
rtcregs->rtsr &= ~RTSR_ale;
|
||||
rtcregs->rtar = 0xffffffff;
|
||||
} else {
|
||||
t = todget(nil);
|
||||
t = t / 1000000000ULL; // nsec to secs
|
||||
if (secs < t)
|
||||
return;
|
||||
secs -= t;
|
||||
iprint("RTC alarm set to %uld seconds from now\n", secs);
|
||||
rtcregs->rtar = rtcregs->rcnr + secs;
|
||||
rtcregs->rtsr|= RTSR_ale;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rtcintr(Ureg*, void*)
|
||||
{
|
||||
/* reset interrupt */
|
||||
rtcregs->rtsr&= ~RTSR_ale;
|
||||
rtcregs->rtsr&= ~RTSR_al;
|
||||
|
||||
rtcregs->rtar = 0;
|
||||
iprint("RTC alarm: %lud\n", rtcregs->rcnr);
|
||||
}
|
||||
|
||||
void
|
||||
delay(int ms)
|
||||
{
|
||||
ulong start;
|
||||
int i;
|
||||
|
||||
if(clockinited){
|
||||
while(ms-- > 0){
|
||||
start = timerregs->oscr;
|
||||
while(timerregs->oscr-start < ClockFreq/1000)
|
||||
;
|
||||
}
|
||||
} else {
|
||||
while(ms-- > 0){
|
||||
for(i = 0; i < 1000; i++)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
microdelay(int µs)
|
||||
{
|
||||
ulong start;
|
||||
int i;
|
||||
|
||||
µs++;
|
||||
if(clockinited){
|
||||
start = timerregs->oscr;
|
||||
while(timerregs->oscr - start < 1UL+(µs*ClockFreq)/1000000UL)
|
||||
;
|
||||
} else {
|
||||
while(µs-- > 0){
|
||||
for(i = 0; i < 10; i++)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* performance measurement ticks. must be low overhead.
|
||||
* doesn't have to count over a second.
|
||||
*/
|
||||
ulong
|
||||
perfticks(void)
|
||||
{
|
||||
return timerregs->oscr;
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
typedef struct Cisdat Cisdat;
|
||||
typedef struct Conf Conf;
|
||||
typedef struct Confmem Confmem;
|
||||
typedef struct FPU FPU;
|
||||
typedef struct FPenv FPenv;
|
||||
typedef struct FPsave FPsave;
|
||||
typedef struct DevConf DevConf;
|
||||
typedef struct Label Label;
|
||||
typedef struct Lock Lock;
|
||||
typedef struct MMU MMU;
|
||||
typedef struct Mach Mach;
|
||||
typedef struct Notsave Notsave;
|
||||
typedef struct Page Page;
|
||||
typedef struct PCMmap PCMmap;
|
||||
typedef struct PCMslot PCMslot;
|
||||
typedef struct PCMconftab PCMconftab;
|
||||
typedef struct PhysUart PhysUart;
|
||||
typedef struct PMMU PMMU;
|
||||
typedef struct Proc Proc;
|
||||
typedef struct Uart Uart;
|
||||
typedef struct Ureg Ureg;
|
||||
typedef struct Vctl Vctl;
|
||||
typedef long Tval;
|
||||
|
||||
#pragma incomplete Ureg
|
||||
|
||||
typedef void IntrHandler(Ureg*, void*);
|
||||
|
||||
#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */
|
||||
|
||||
/*
|
||||
* parameters for sysproc.c
|
||||
*/
|
||||
#define AOUT_MAGIC (E_MAGIC)
|
||||
|
||||
struct Lock
|
||||
{
|
||||
ulong key;
|
||||
ulong sr;
|
||||
ulong pc;
|
||||
Proc *p;
|
||||
Mach *m;
|
||||
ushort isilock;
|
||||
};
|
||||
|
||||
struct Label
|
||||
{
|
||||
ulong sp;
|
||||
ulong pc;
|
||||
};
|
||||
|
||||
/*
|
||||
* FPsave.status
|
||||
*/
|
||||
enum
|
||||
{
|
||||
FPinit,
|
||||
FPactive,
|
||||
FPinactive,
|
||||
};
|
||||
struct FPsave
|
||||
{
|
||||
ulong status;
|
||||
ulong control;
|
||||
ulong regs[8][3]; /* emulated fp */
|
||||
};
|
||||
|
||||
struct Confmem
|
||||
{
|
||||
ulong base;
|
||||
ulong npage;
|
||||
ulong limit;
|
||||
ulong kbase;
|
||||
ulong klimit;
|
||||
};
|
||||
|
||||
struct Conf
|
||||
{
|
||||
ulong nmach; /* processors */
|
||||
ulong nproc; /* processes */
|
||||
Confmem mem[2];
|
||||
ulong npage; /* total physical pages of memory */
|
||||
ulong upages; /* user page pool */
|
||||
ulong nimage; /* number of page cache image headers */
|
||||
ulong nswap; /* number of swap pages */
|
||||
int nswppo; /* max # of pageouts per segment pass */
|
||||
ulong copymode; /* 0 is copy on write, 1 is copy on reference */
|
||||
int monitor;
|
||||
ulong ialloc; /* bytes available for interrupt time allocation */
|
||||
ulong pipeqsize; /* size in bytes of pipe queues */
|
||||
ulong hz; /* processor cycle freq */
|
||||
ulong mhz;
|
||||
};
|
||||
|
||||
/*
|
||||
* MMU stuff in proc
|
||||
*/
|
||||
enum
|
||||
{
|
||||
NCOLOR= 1, /* 1 level cache, don't worry about VCE's */
|
||||
Nmeg= 32, /* maximum size of user space */
|
||||
};
|
||||
|
||||
struct PMMU
|
||||
{
|
||||
Page *l1page[Nmeg]; /* this's process' level 1 entries */
|
||||
ulong l1table[Nmeg]; /* ... */
|
||||
Page *mmufree; /* free mmu pages */
|
||||
};
|
||||
|
||||
/*
|
||||
* things saved in the Proc structure during a notify
|
||||
*/
|
||||
struct Notsave
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
#include "../port/portdat.h"
|
||||
|
||||
struct Mach
|
||||
{
|
||||
int machno; /* physical id of processor */
|
||||
ulong splpc; /* pc of last caller to splhi */
|
||||
|
||||
Proc *proc; /* current process */
|
||||
ulong mmupid; /* process id currently in mmu & cache */
|
||||
|
||||
ulong ticks; /* of the clock since boot time */
|
||||
Label sched; /* scheduler wakeup */
|
||||
Lock alarmlock; /* access to alarm list */
|
||||
void* alarm; /* alarms bound to this clock */
|
||||
int inclockintr;
|
||||
|
||||
Proc* readied; /* for runproc */
|
||||
ulong schedticks; /* next forced context switch */
|
||||
|
||||
/* stats */
|
||||
int tlbfault;
|
||||
int tlbpurge;
|
||||
int pfault;
|
||||
int cs;
|
||||
int syscall;
|
||||
int load;
|
||||
int intr;
|
||||
vlong fastclock; /* last sampled value */
|
||||
uvlong inidle; /* time spent in idlehands() */
|
||||
ulong spuriousintr;
|
||||
int lastintr;
|
||||
int ilockdepth;
|
||||
Perf perf; /* performance counters */
|
||||
|
||||
int flushmmu; /* make current proc flush it's mmu state */
|
||||
Proc *pid2proc[31]; /* what proc holds what pid */
|
||||
int lastpid; /* highest assigned pid slot */
|
||||
|
||||
int cpumhz; /* speed of cpu */
|
||||
vlong cpuhz; /* ... */
|
||||
uvlong cyclefreq; /* Frequency of user readable cycle counter */
|
||||
|
||||
/* save areas for exceptions */
|
||||
ulong sfiq[5];
|
||||
ulong sirq[5];
|
||||
ulong sund[5];
|
||||
ulong sabt[5];
|
||||
|
||||
int stack[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* Fake kmap since we direct map dram
|
||||
*/
|
||||
typedef void KMap;
|
||||
#define VA(k) ((ulong)(k))
|
||||
#define kmap(p) (KMap*)((p)->pa)
|
||||
#define kunmap(k)
|
||||
|
||||
struct
|
||||
{
|
||||
Lock;
|
||||
char machs[MAXMACH]; /* active CPUs */
|
||||
int exiting; /* shutdown */
|
||||
}active;
|
||||
|
||||
#define MACHP(n) ((Mach *)(MACHADDR+(n)*BY2PG))
|
||||
|
||||
extern Mach *m;
|
||||
extern Proc *up;
|
||||
|
||||
enum
|
||||
{
|
||||
OneMeg= 1024*1024,
|
||||
};
|
||||
|
||||
/*
|
||||
* PCMCIA structures known by both port/cis.c and the pcmcia driver
|
||||
*/
|
||||
|
||||
/*
|
||||
* Map between ISA memory space and PCMCIA card memory space.
|
||||
*/
|
||||
struct PCMmap {
|
||||
ulong ca; /* card address */
|
||||
ulong cea; /* card end address */
|
||||
ulong isa; /* local virtual address */
|
||||
int len; /* length of the ISA area */
|
||||
int attr; /* attribute memory */
|
||||
};
|
||||
|
||||
/*
|
||||
* a PCMCIA configuration entry
|
||||
*/
|
||||
struct PCMconftab
|
||||
{
|
||||
int index;
|
||||
ushort irqs; /* legal irqs */
|
||||
uchar irqtype;
|
||||
uchar bit16; /* true for 16 bit access */
|
||||
struct {
|
||||
ulong start;
|
||||
ulong len;
|
||||
} io[16];
|
||||
int nio;
|
||||
uchar vpp1;
|
||||
uchar vpp2;
|
||||
uchar memwait;
|
||||
ulong maxwait;
|
||||
ulong readywait;
|
||||
ulong otherwait;
|
||||
};
|
||||
|
||||
/*
|
||||
* PCMCIA card slot
|
||||
*/
|
||||
struct PCMslot
|
||||
{
|
||||
RWlock;
|
||||
|
||||
Ref ref;
|
||||
|
||||
long memlen; /* memory length */
|
||||
uchar slotno; /* slot number */
|
||||
void *regs; /* i/o registers */
|
||||
void *mem; /* memory */
|
||||
void *attr; /* attribute memory */
|
||||
|
||||
/* status */
|
||||
uchar occupied; /* card in the slot */
|
||||
uchar configed; /* card configured */
|
||||
uchar inserted; /* card just inserted */
|
||||
|
||||
Dev *dev; /* set in ctlwrite `configure' */
|
||||
|
||||
/* cis info */
|
||||
int cisread; /* set when the cis has been read */
|
||||
char verstr[512]; /* version string */
|
||||
int ncfg; /* number of configurations */
|
||||
struct {
|
||||
ushort cpresent; /* config registers present */
|
||||
ulong caddr; /* relative address of config registers */
|
||||
} cfg[8];
|
||||
int nctab; /* number of config table entries */
|
||||
PCMconftab ctab[8];
|
||||
PCMconftab *def; /* default conftab */
|
||||
|
||||
/* maps are fixed */
|
||||
PCMmap memmap;
|
||||
PCMmap attrmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* hardware info about a device
|
||||
*/
|
||||
typedef struct {
|
||||
ulong port;
|
||||
int size;
|
||||
} Devport;
|
||||
|
||||
struct DevConf
|
||||
{
|
||||
RWlock; /* write: configure/unconfigure/suspend; read: normal access */
|
||||
ulong mem; /* mapped memory address */
|
||||
Devport *ports; /* ports[0]: mapped i/o regs, access size */
|
||||
int nports; /* always 1 for the bitsy */
|
||||
int itype; /* type of interrupt */
|
||||
ulong intnum; /* interrupt number */
|
||||
char *type; /* card type, mallocated */
|
||||
};
|
||||
|
|
@ -1,291 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
|
||||
/*
|
||||
* /tmp/latin1.6x13, in uncompressed form
|
||||
*/
|
||||
uchar
|
||||
defontdata[] =
|
||||
{
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x35,0x33,0x36,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x33,0x20,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x41,0x0e,0x00,0x60,0xc2,0x0a,0x00,
|
||||
0x00,0x00,0x60,0xc2,0x00,0x60,0xc2,0x00,0x00,0xa6,0x0c,0x20,0xa0,0x00,0x01,0x83,
|
||||
0x08,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0x0c,0x00,0x00,0x00,0x00,0x0c,0x00,0x03,0x00,0x00,0x00,0x3f,
|
||||
0x30,0x03,0x1c,0x30,0x00,0x00,0x00,0x83,0x00,0x41,0x02,0x00,0x31,0x85,0x14,0x51,
|
||||
0xc0,0x00,0x31,0x85,0x14,0x31,0x85,0x14,0x01,0x43,0x18,0x51,0x45,0x00,0x08,0xc6,
|
||||
0x14,0x51,0x86,0x1c,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,
|
||||
0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x08,0x00,0x0c,0x00,0x73,0xe0,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x85,0x00,0x71,0x24,0x0c,0x11,0x00,0x00,0x00,0x00,0x02,
|
||||
0x20,0x87,0x3e,0x13,0xe7,0x3e,0x71,0xc0,0x00,0x08,0x08,0x1c,0x70,0x8f,0x1c,0xf3,
|
||||
0xef,0x9c,0x89,0xc3,0xa2,0x82,0x28,0x9c,0xf1,0xcf,0x1c,0xfa,0x28,0xa2,0x8a,0x2f,
|
||||
0x9c,0x81,0xc2,0x00,0x30,0x08,0x00,0x08,0x03,0x00,0x80,0x00,0x20,0x60,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x23,0x04,0xaa,0x8f,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0x0c,0x80,0x00,0x02,0x22,0x12,0x00,0xc0,0x80,0x00,0x03,0x00,
|
||||
0x48,0x04,0x82,0x60,0x06,0xc0,0x00,0x84,0x80,0x49,0x24,0x08,0x00,0x08,0x80,0x01,
|
||||
0x40,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x88,0x00,0x00,0x70,0x00,
|
||||
0x00,0x00,0x04,0x22,0x60,0xc5,0x0a,0x00,0x00,0x00,0x60,0xc5,0x00,0x60,0xc5,0x00,
|
||||
0x09,0x46,0x0c,0x51,0x40,0x00,0x01,0x83,0x14,0x00,0xc8,0x00,0x1b,0xe0,0x00,0x03,
|
||||
0x84,0x00,0xc0,0x00,0x00,0xf0,0x0e,0x38,0xc3,0x0c,0x30,0xc2,0x4e,0x38,0x63,0x8e,
|
||||
0x38,0xe3,0x8c,0x28,0x00,0x85,0x14,0xa2,0xaa,0x08,0x20,0x82,0x00,0x00,0x00,0x02,
|
||||
0x51,0x88,0x82,0x12,0x08,0x82,0x8a,0x20,0x00,0x10,0x04,0x22,0x89,0x44,0xa2,0x4a,
|
||||
0x08,0x22,0x88,0x81,0x22,0x82,0x2c,0xa2,0x8a,0x28,0xa2,0x22,0x28,0xa2,0x8a,0x20,
|
||||
0x90,0x80,0x45,0x00,0x10,0x08,0x00,0x08,0x04,0x80,0x80,0x81,0x20,0x20,0x00,0x00,
|
||||
0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x08,0x20,0x8a,0x94,0x77,0xff,0xff,0x1e,
|
||||
0xff,0xcf,0xff,0xff,0xc3,0xfc,0x71,0xcf,0x3c,0xf3,0xcf,0x6c,0x71,0xe7,0x1c,0x71,
|
||||
0xc7,0x3c,0x73,0xd7,0x00,0x02,0x00,0x8a,0x22,0x10,0x51,0x23,0x82,0x00,0x04,0x80,
|
||||
0x48,0x01,0x0c,0x00,0x0a,0x80,0x00,0x84,0xa0,0x51,0x42,0x80,0x71,0xc7,0x1c,0x71,
|
||||
0xc7,0xa2,0xfb,0xef,0xbe,0x71,0xc7,0x1c,0x4a,0x27,0x1c,0x71,0xc7,0x00,0x9a,0x28,
|
||||
0xa2,0x8a,0x27,0x22,0x31,0x88,0x94,0x51,0xc0,0x00,0x31,0x88,0x94,0x31,0x88,0x94,
|
||||
0x7e,0x83,0x18,0x8a,0x85,0x0c,0x00,0xc6,0x22,0x51,0x88,0x14,0x9f,0xee,0x38,0xe2,
|
||||
0x0a,0x08,0xa2,0x88,0x22,0x81,0xc8,0x20,0xa2,0x8a,0x28,0xa3,0x48,0x20,0x92,0x08,
|
||||
0x20,0x82,0x0a,0x28,0x00,0x85,0x14,0xa1,0x4a,0x10,0x20,0x8a,0x88,0x00,0x00,0x04,
|
||||
0x8a,0x88,0x84,0x32,0x08,0x04,0x8a,0x22,0x08,0x20,0x02,0x22,0x8a,0x24,0xa0,0x4a,
|
||||
0x08,0x20,0x88,0x81,0x24,0x83,0x6c,0xa2,0x8a,0x28,0xa0,0x22,0x28,0xa2,0x51,0x41,
|
||||
0x10,0x40,0x48,0x80,0x08,0x08,0x00,0x08,0x04,0x00,0x80,0x00,0x20,0x20,0x00,0x00,
|
||||
0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x08,0x20,0x89,0x2a,0x74,0x71,0xc7,0x7d,
|
||||
0x7d,0xd7,0x5d,0xf7,0x5f,0x8d,0xf7,0xd7,0x5d,0x75,0xd7,0x2d,0xf7,0xdb,0x7d,0xf7,
|
||||
0xdf,0x5d,0xf5,0xd7,0x00,0x82,0x0c,0x71,0x42,0x10,0x02,0x14,0x84,0x00,0x08,0x40,
|
||||
0x48,0x82,0x02,0x00,0x0a,0x80,0x00,0x83,0x10,0x20,0x8d,0x08,0x8a,0x28,0xa2,0x8a,
|
||||
0x2a,0x20,0x82,0x08,0x20,0x20,0x82,0x08,0x4b,0x28,0xa2,0x8a,0x28,0x80,0x9a,0x28,
|
||||
0xa2,0x89,0x44,0xa6,0x00,0x00,0x00,0x01,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x08,0x00,0x00,0x00,0x00,0x0c,0x08,0x00,0x00,0x00,0x08,0x00,0xff,0xe8,0x20,0x83,
|
||||
0x8a,0x1c,0xc2,0x88,0x22,0xe2,0x0e,0x38,0xa2,0x8a,0x28,0xa2,0xce,0x30,0x83,0x8e,
|
||||
0x38,0xe2,0x8c,0x28,0x00,0x80,0x3e,0x70,0x44,0x00,0x40,0x4f,0x88,0x00,0x00,0x04,
|
||||
0x88,0x80,0x88,0x52,0xc8,0x04,0x8a,0x27,0x1c,0x43,0xe1,0x02,0x9a,0x24,0xa0,0x4a,
|
||||
0x08,0x20,0x88,0x81,0x28,0x82,0xaa,0xa2,0x8a,0x28,0xa0,0x22,0x28,0xa2,0x51,0x41,
|
||||
0x10,0x40,0x40,0x00,0x01,0xcf,0x1c,0x79,0xc4,0x1c,0xb1,0x83,0x24,0x23,0x4b,0x1c,
|
||||
0xf1,0xeb,0x1c,0xf2,0x28,0xa2,0x8a,0x2f,0x88,0x20,0x80,0x14,0xf5,0xf7,0xdf,0x1d,
|
||||
0x78,0xcf,0x5d,0xf7,0x47,0x7c,0x71,0xd7,0x5d,0x75,0xd7,0x4c,0x73,0xdf,0x1c,0x71,
|
||||
0xc7,0x3d,0x73,0xd7,0x00,0x87,0x12,0x51,0x42,0x1c,0x02,0xd4,0x8a,0xf8,0x0b,0x40,
|
||||
0x30,0x87,0x9c,0x01,0x2a,0x80,0x00,0x80,0x28,0x49,0x42,0x88,0x8a,0x28,0xa2,0x8a,
|
||||
0x2a,0x20,0x82,0x08,0x20,0x20,0x82,0x08,0x4b,0x28,0xa2,0x8a,0x28,0xa1,0xaa,0x28,
|
||||
0xa2,0x89,0x44,0xac,0x71,0xc7,0x1c,0x71,0xcf,0x1c,0x71,0xc7,0x1c,0x61,0x86,0x18,
|
||||
0x7a,0xc7,0x1c,0x71,0xc7,0x00,0x72,0x28,0xa2,0x8a,0x2f,0x22,0x1b,0xee,0x38,0xc2,
|
||||
0x0e,0x1c,0xa3,0x88,0x14,0x82,0x02,0x08,0xa2,0x8a,0x28,0xa2,0x42,0x20,0x92,0x02,
|
||||
0x20,0x82,0x8a,0x28,0x00,0x80,0x14,0x28,0x8a,0x00,0x40,0x47,0x3e,0x03,0xe0,0x08,
|
||||
0x88,0x81,0x1c,0x53,0x2f,0x08,0x71,0xe2,0x08,0x80,0x00,0x84,0xaa,0x27,0x20,0x4b,
|
||||
0xcf,0x20,0xf8,0x81,0x30,0x82,0xaa,0xa2,0xf2,0x2f,0x1c,0x22,0x25,0x2a,0x20,0x82,
|
||||
0x10,0x20,0x40,0x00,0x00,0x28,0xa2,0x8a,0x2f,0x22,0xc8,0x81,0x28,0x22,0xac,0xa2,
|
||||
0x8a,0x2c,0xa2,0x42,0x28,0xa2,0x52,0x21,0x30,0x20,0x60,0x2a,0xec,0x71,0xcf,0x7c,
|
||||
0x78,0xd7,0x1d,0xfa,0xdf,0x7f,0x7d,0xd7,0x5d,0x75,0xd7,0x6f,0x77,0xdb,0x7f,0x77,
|
||||
0xdf,0x5d,0x75,0xd7,0x00,0x8a,0x90,0x50,0x80,0x12,0x02,0x93,0x94,0x09,0xea,0x40,
|
||||
0x03,0xe0,0x00,0x01,0x26,0x8c,0x00,0x07,0x94,0x9a,0xa5,0x90,0x8a,0x28,0xa2,0x8a,
|
||||
0x2b,0xa0,0xf3,0xcf,0x3c,0x20,0x82,0x08,0xea,0xa8,0xa2,0x8a,0x28,0x92,0xaa,0x28,
|
||||
0xa2,0x88,0x85,0xa6,0x08,0x20,0x82,0x08,0x22,0xa2,0x8a,0x28,0xa2,0x20,0x82,0x08,
|
||||
0x8b,0x28,0xa2,0x8a,0x28,0x9e,0x9a,0x28,0xa2,0x8a,0x28,0xa2,0x3b,0xe2,0x20,0x83,
|
||||
0x8a,0x14,0xc2,0x8e,0x08,0x81,0xce,0x38,0xc3,0x0c,0x30,0xc2,0x4e,0x38,0x63,0x8e,
|
||||
0x38,0x83,0x8a,0x10,0x00,0x80,0x3e,0x29,0x09,0x80,0x40,0x4f,0x88,0x00,0x00,0x10,
|
||||
0x88,0x82,0x02,0x90,0x28,0x88,0x88,0x20,0x00,0x40,0x01,0x08,0xab,0xe4,0xa0,0x4a,
|
||||
0x08,0x26,0x88,0x81,0x28,0x82,0x29,0xa2,0x82,0x2a,0x02,0x22,0x25,0x2a,0x50,0x84,
|
||||
0x10,0x10,0x40,0x00,0x01,0xe8,0xa0,0x8b,0xe4,0x22,0x88,0x81,0x30,0x22,0xa8,0xa2,
|
||||
0x8a,0x28,0x18,0x42,0x28,0xaa,0x22,0x22,0x08,0x20,0x80,0x14,0xdf,0x77,0xdf,0x1d,
|
||||
0x7a,0xcf,0x5c,0x7d,0xdf,0x8c,0x71,0xcf,0x3c,0xf3,0xcf,0x6c,0x71,0xe7,0x1c,0x71,
|
||||
0xdf,0x5c,0x75,0xef,0x00,0x8a,0x3c,0x53,0xe2,0x0e,0x02,0xd0,0x28,0x09,0xea,0x40,
|
||||
0x00,0x80,0x00,0x01,0x22,0x8c,0x00,0x00,0x0a,0x28,0x2a,0xa0,0xfb,0xef,0xbe,0xfb,
|
||||
0xee,0x20,0x82,0x08,0x20,0x20,0x82,0x08,0x4a,0xa8,0xa2,0x8a,0x28,0x8c,0xaa,0x28,
|
||||
0xa2,0x88,0x86,0x22,0x79,0xe7,0x9e,0x79,0xe7,0xa0,0xfb,0xef,0xbe,0x20,0x82,0x08,
|
||||
0x8a,0x28,0xa2,0x8a,0x28,0x9e,0xaa,0x28,0xa2,0x8a,0x28,0xa2,0x33,0xee,0x38,0xf0,
|
||||
0xc5,0x3e,0x72,0x87,0x00,0x79,0xc0,0x00,0x20,0x01,0x0e,0x18,0xa4,0x98,0x49,0x16,
|
||||
0x1c,0x71,0xc7,0x1c,0x00,0x80,0x14,0x71,0x49,0x00,0x20,0x8a,0x88,0x00,0x00,0x10,
|
||||
0x88,0x84,0x02,0xf8,0x28,0x90,0x88,0x20,0x00,0x23,0xe2,0x08,0xb2,0x24,0xa0,0x4a,
|
||||
0x08,0x22,0x88,0x81,0x24,0x82,0x29,0xa2,0x82,0x29,0x02,0x22,0x25,0x2a,0x50,0x84,
|
||||
0x10,0x10,0x40,0x00,0x02,0x28,0xa0,0x8a,0x04,0x22,0x88,0x81,0x28,0x22,0xa8,0xa2,
|
||||
0x8a,0x28,0x04,0x42,0x25,0x2a,0x22,0x64,0x08,0x20,0x80,0x2a,0xdc,0x71,0xc3,0xce,
|
||||
0xb0,0x63,0x5e,0x3f,0xe1,0x8f,0xff,0xf7,0xff,0xbc,0x79,0xd6,0xd9,0xed,0xba,0x78,
|
||||
0xe3,0x8e,0x38,0xe3,0x00,0x8a,0x08,0x50,0x82,0x02,0x02,0x17,0x94,0x08,0x08,0x40,
|
||||
0x00,0x80,0x00,0x01,0x22,0x80,0x00,0x00,0x14,0x48,0x44,0xa2,0x8a,0x28,0xa2,0x8a,
|
||||
0x2a,0x20,0x82,0x08,0x20,0x20,0x82,0x08,0x4a,0x68,0xa2,0x8a,0x28,0x8c,0xca,0x28,
|
||||
0xa2,0x88,0x84,0x22,0x8a,0x28,0xa2,0x8a,0x2a,0x20,0x82,0x08,0x20,0x20,0x82,0x08,
|
||||
0x8a,0x28,0xa2,0x8a,0x28,0x80,0xaa,0x28,0xa2,0x8a,0x68,0xa6,0x33,0xe4,0x92,0x41,
|
||||
0x25,0x08,0x41,0xc4,0x3e,0x41,0x23,0x04,0x20,0x42,0x82,0x28,0xa6,0x94,0x69,0xb5,
|
||||
0x10,0x41,0x04,0x10,0x00,0x00,0x14,0x22,0xa6,0x80,0x20,0x82,0x00,0x30,0x02,0x20,
|
||||
0x50,0x88,0x22,0x12,0x28,0x90,0x8a,0x22,0x0c,0x10,0x04,0x00,0x82,0x24,0xa2,0x4a,
|
||||
0x08,0x22,0x88,0x89,0x22,0x82,0x28,0xa2,0x82,0xa8,0xa2,0x22,0x22,0x36,0x88,0x88,
|
||||
0x10,0x08,0x40,0x00,0x02,0x28,0xa2,0x8a,0x24,0x1e,0x88,0x81,0x24,0x22,0xa8,0xa2,
|
||||
0xf1,0xe8,0x22,0x4a,0x65,0x2a,0x51,0xa8,0x08,0x20,0x80,0x14,0xfe,0xdb,0x6f,0xb6,
|
||||
0xbd,0xef,0x8e,0xf0,0x6f,0xb7,0x3e,0xf7,0xef,0x5f,0x75,0xd6,0x5a,0xe5,0x92,0xbb,
|
||||
0xef,0xbe,0xfb,0xef,0x00,0x8a,0xbc,0x73,0xe2,0x02,0x01,0x20,0x0a,0x00,0x04,0x80,
|
||||
0x03,0xe0,0x00,0x01,0x62,0x80,0x00,0x00,0x28,0x78,0x87,0xa2,0x8a,0x28,0xa2,0x8a,
|
||||
0x2a,0x22,0x82,0x08,0x20,0x20,0x82,0x08,0x4a,0x68,0xa2,0x8a,0x28,0x92,0xca,0x28,
|
||||
0xa2,0x88,0x84,0x26,0x8a,0x28,0xa2,0x8a,0x2a,0xa2,0x8a,0x28,0xa2,0x20,0x82,0x08,
|
||||
0x8a,0x28,0xa2,0x8a,0x28,0x8c,0xca,0x69,0xa6,0x99,0xa8,0x9a,0x03,0xe3,0x0c,0x61,
|
||||
0x26,0x00,0x70,0x86,0x08,0x71,0xc4,0x84,0x20,0x41,0x04,0x48,0xc5,0x98,0x59,0x56,
|
||||
0x1c,0x71,0xc7,0x1c,0x00,0x80,0x00,0x02,0x40,0x00,0x11,0x00,0x00,0x20,0x07,0x20,
|
||||
0x23,0xef,0x9c,0x11,0xc7,0x10,0x71,0xc7,0x08,0x08,0x08,0x08,0x7a,0x2f,0x1c,0xf3,
|
||||
0xe8,0x1c,0x89,0xc6,0x22,0xfa,0x28,0x9c,0x81,0xc8,0x9c,0x21,0xc2,0x22,0x88,0x8f,
|
||||
0x9c,0x09,0xc0,0x00,0x01,0xef,0x1c,0x79,0xc4,0x02,0x89,0xc9,0x22,0x72,0x28,0x9c,
|
||||
0x80,0x28,0x1c,0x31,0xa2,0x14,0x88,0x2f,0x86,0x23,0x00,0x2a,0xdf,0x3c,0xe7,0xb6,
|
||||
0x7f,0xe3,0xde,0x7d,0xe3,0x8e,0xde,0xf7,0xef,0xbe,0xed,0xce,0x99,0xe9,0xaa,0x78,
|
||||
0xe3,0x8e,0x38,0xe3,0xc0,0x87,0x2a,0x88,0x82,0x12,0x00,0xc0,0x04,0x00,0x03,0x00,
|
||||
0x00,0x00,0x00,0x01,0xa2,0x80,0x10,0x00,0x10,0x08,0xe0,0x9c,0x8a,0x28,0xa2,0x8a,
|
||||
0x2b,0x9c,0xfb,0xef,0xbe,0x71,0xc7,0x1c,0xf2,0x27,0x1c,0x71,0xc7,0x21,0x71,0xc7,
|
||||
0x1c,0x70,0x84,0x2c,0x79,0xe7,0x9e,0x79,0xe7,0x1c,0x71,0xc7,0x1c,0x71,0xc7,0x1c,
|
||||
0x7a,0x27,0x1c,0x71,0xc7,0x0c,0x71,0xa6,0x9a,0x68,0x2f,0x02,0x03,0xe3,0x0c,0x40,
|
||||
0xc5,0x00,0x10,0x84,0x08,0x41,0x44,0x84,0x20,0x42,0x02,0x7c,0xa4,0x94,0x49,0x15,
|
||||
0x04,0x10,0x41,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x02,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x09,0x00,0x00,0x00,0x00,
|
||||
0x80,0x20,0x00,0x00,0x00,0x00,0x02,0x20,0x00,0x00,0x00,0x14,0xff,0x3c,0xef,0xce,
|
||||
0xbf,0xfb,0xde,0xfd,0xef,0xae,0xde,0xf7,0xef,0x7f,0x60,0xd6,0xda,0xed,0xba,0xbe,
|
||||
0xfb,0xef,0xbe,0xfb,0xc0,0x02,0x38,0x00,0x00,0x0c,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x02,0x00,0x00,0x10,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,
|
||||
0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x02,0x28,0x22,0x00,0x04,0x92,0x40,
|
||||
0x24,0x80,0x70,0x84,0x08,0x41,0x23,0x04,0x38,0x43,0x8e,0x08,0x94,0x98,0x49,0x16,
|
||||
0x1c,0x71,0xc7,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x06,0x00,0x00,0x00,0x00,
|
||||
0x80,0x20,0x00,0x00,0x00,0x00,0x01,0xc0,0x00,0x00,0x00,0x2a,0x02,0xdb,0x6f,0xf6,
|
||||
0xdf,0xe3,0xde,0xfd,0xef,0xb7,0x3e,0xf1,0xef,0x1c,0x7d,0xda,0xd9,0xed,0xba,0x78,
|
||||
0xe3,0x8e,0x38,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xc8,0x1c,
|
||||
0x20,0x20,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x32,0x35,0x36,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x31,0x33,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x31,
|
||||
0x20,0x00,0x00,0x02,0x0a,0x00,0x06,0x06,0x00,0x02,0x0c,0x00,0x06,0x0c,0x00,0x04,
|
||||
0x0d,0x00,0x06,0x12,0x00,0x04,0x0d,0x00,0x06,0x18,0x00,0x04,0x0d,0x00,0x06,0x1e,
|
||||
0x00,0x03,0x0d,0x00,0x06,0x24,0x00,0x03,0x0d,0x00,0x06,0x2a,0x00,0x04,0x0a,0x00,
|
||||
0x06,0x30,0x00,0x03,0x0d,0x00,0x06,0x36,0x00,0x04,0x0d,0x00,0x06,0x3c,0x00,0x04,
|
||||
0x0d,0x00,0x06,0x42,0x00,0x04,0x0d,0x00,0x06,0x48,0x00,0x03,0x0d,0x00,0x06,0x4e,
|
||||
0x00,0x04,0x0d,0x00,0x06,0x54,0x00,0x03,0x0d,0x00,0x06,0x5a,0x00,0x03,0x0d,0x00,
|
||||
0x06,0x60,0x00,0x03,0x0d,0x00,0x06,0x66,0x00,0x03,0x0d,0x00,0x06,0x6c,0x00,0x03,
|
||||
0x0d,0x00,0x06,0x72,0x00,0x03,0x0d,0x00,0x06,0x78,0x00,0x03,0x0d,0x00,0x06,0x7e,
|
||||
0x00,0x03,0x0d,0x00,0x06,0x84,0x00,0x03,0x0d,0x00,0x06,0x8a,0x00,0x03,0x0d,0x00,
|
||||
0x06,0x90,0x00,0x03,0x0d,0x00,0x06,0x96,0x00,0x03,0x0d,0x00,0x06,0x9c,0x00,0x03,
|
||||
0x0d,0x00,0x06,0xa2,0x00,0x03,0x0d,0x00,0x06,0xa8,0x00,0x03,0x0d,0x00,0x06,0xae,
|
||||
0x00,0x03,0x0d,0x00,0x06,0xb4,0x00,0x03,0x0d,0x00,0x06,0xba,0x00,0x03,0x0d,0x00,
|
||||
0x06,0xc0,0x00,0x00,0x00,0x00,0x06,0xc6,0x00,0x02,0x0b,0x00,0x06,0xcc,0x00,0x02,
|
||||
0x05,0x00,0x06,0xd2,0x00,0x03,0x0a,0x00,0x06,0xd8,0x00,0x01,0x0a,0x00,0x06,0xde,
|
||||
0x00,0x02,0x0b,0x00,0x06,0xe4,0x00,0x02,0x0a,0x00,0x06,0xea,0x00,0x02,0x05,0x00,
|
||||
0x06,0xf0,0x00,0x02,0x0b,0x00,0x06,0xf6,0x00,0x02,0x0b,0x00,0x06,0xfc,0x00,0x03,
|
||||
0x0a,0x00,0x06,0x02,0x01,0x04,0x09,0x00,0x06,0x08,0x01,0x09,0x0c,0x00,0x06,0x0e,
|
||||
0x01,0x06,0x07,0x00,0x06,0x14,0x01,0x09,0x0c,0x00,0x06,0x1a,0x01,0x02,0x0b,0x00,
|
||||
0x06,0x20,0x01,0x02,0x0b,0x00,0x06,0x26,0x01,0x02,0x0b,0x00,0x06,0x2c,0x01,0x02,
|
||||
0x0b,0x00,0x06,0x32,0x01,0x02,0x0b,0x00,0x06,0x38,0x01,0x02,0x0b,0x00,0x06,0x3e,
|
||||
0x01,0x02,0x0b,0x00,0x06,0x44,0x01,0x02,0x0b,0x00,0x06,0x4a,0x01,0x02,0x0b,0x00,
|
||||
0x06,0x50,0x01,0x02,0x0b,0x00,0x06,0x56,0x01,0x02,0x0b,0x00,0x06,0x5c,0x01,0x00,
|
||||
0x0d,0x00,0x06,0x62,0x01,0x00,0x0d,0x00,0x06,0x68,0x01,0x02,0x0b,0x00,0x06,0x6e,
|
||||
0x01,0x00,0x0d,0x00,0x06,0x74,0x01,0x02,0x0b,0x00,0x06,0x7a,0x01,0x02,0x0b,0x00,
|
||||
0x06,0x80,0x01,0x02,0x0b,0x00,0x06,0x86,0x01,0x02,0x0b,0x00,0x06,0x8c,0x01,0x02,
|
||||
0x0b,0x00,0x06,0x92,0x01,0x02,0x0b,0x00,0x06,0x98,0x01,0x02,0x0b,0x00,0x06,0x9e,
|
||||
0x01,0x02,0x0b,0x00,0x06,0xa4,0x01,0x02,0x0b,0x00,0x06,0xaa,0x01,0x02,0x0b,0x00,
|
||||
0x06,0xb0,0x01,0x02,0x0b,0x00,0x06,0xb6,0x01,0x02,0x0b,0x00,0x06,0xbc,0x01,0x02,
|
||||
0x0b,0x00,0x06,0xc2,0x01,0x02,0x0b,0x00,0x06,0xc8,0x01,0x02,0x0b,0x00,0x06,0xce,
|
||||
0x01,0x02,0x0b,0x00,0x06,0xd4,0x01,0x02,0x0b,0x00,0x06,0xda,0x01,0x02,0x0b,0x00,
|
||||
0x06,0xe0,0x01,0x02,0x0b,0x00,0x06,0xe6,0x01,0x02,0x0c,0x00,0x06,0xec,0x01,0x02,
|
||||
0x0b,0x00,0x06,0xf2,0x01,0x02,0x0b,0x00,0x06,0xf8,0x01,0x02,0x0b,0x00,0x06,0xfe,
|
||||
0x01,0x02,0x0b,0x00,0x06,0x04,0x02,0x02,0x0b,0x00,0x06,0x0a,0x02,0x02,0x0b,0x00,
|
||||
0x06,0x10,0x02,0x02,0x0b,0x00,0x06,0x16,0x02,0x02,0x0b,0x00,0x06,0x1c,0x02,0x02,
|
||||
0x0b,0x00,0x06,0x22,0x02,0x02,0x0b,0x00,0x06,0x28,0x02,0x02,0x0b,0x00,0x06,0x2e,
|
||||
0x02,0x02,0x0b,0x00,0x06,0x34,0x02,0x02,0x05,0x00,0x06,0x3a,0x02,0x0b,0x0c,0x00,
|
||||
0x06,0x40,0x02,0x02,0x05,0x00,0x06,0x46,0x02,0x05,0x0b,0x00,0x06,0x4c,0x02,0x02,
|
||||
0x0b,0x00,0x06,0x52,0x02,0x05,0x0b,0x00,0x06,0x58,0x02,0x02,0x0b,0x00,0x06,0x5e,
|
||||
0x02,0x05,0x0b,0x00,0x06,0x64,0x02,0x02,0x0b,0x00,0x06,0x6a,0x02,0x05,0x0d,0x00,
|
||||
0x06,0x70,0x02,0x02,0x0b,0x00,0x06,0x76,0x02,0x03,0x0b,0x00,0x06,0x7c,0x02,0x03,
|
||||
0x0d,0x00,0x06,0x82,0x02,0x02,0x0b,0x00,0x06,0x88,0x02,0x02,0x0b,0x00,0x06,0x8e,
|
||||
0x02,0x05,0x0b,0x00,0x06,0x94,0x02,0x05,0x0b,0x00,0x06,0x9a,0x02,0x05,0x0b,0x00,
|
||||
0x06,0xa0,0x02,0x05,0x0d,0x00,0x06,0xa6,0x02,0x05,0x0d,0x00,0x06,0xac,0x02,0x05,
|
||||
0x0b,0x00,0x06,0xb2,0x02,0x05,0x0b,0x00,0x06,0xb8,0x02,0x03,0x0b,0x00,0x06,0xbe,
|
||||
0x02,0x05,0x0b,0x00,0x06,0xc4,0x02,0x05,0x0b,0x00,0x06,0xca,0x02,0x05,0x0b,0x00,
|
||||
0x06,0xd0,0x02,0x05,0x0b,0x00,0x06,0xd6,0x02,0x05,0x0d,0x00,0x06,0xdc,0x02,0x05,
|
||||
0x0b,0x00,0x06,0xe2,0x02,0x02,0x0b,0x00,0x06,0xe8,0x02,0x02,0x0b,0x00,0x06,0xee,
|
||||
0x02,0x02,0x0b,0x00,0x06,0xf4,0x02,0x02,0x05,0x00,0x06,0xfa,0x02,0x00,0x0d,0x00,
|
||||
0x06,0x00,0x03,0x00,0x0c,0x00,0x06,0x06,0x03,0x00,0x0d,0x00,0x06,0x0c,0x03,0x00,
|
||||
0x0d,0x00,0x06,0x12,0x03,0x00,0x0d,0x00,0x06,0x18,0x03,0x00,0x0d,0x00,0x06,0x1e,
|
||||
0x03,0x00,0x0d,0x00,0x06,0x24,0x03,0x00,0x0d,0x00,0x06,0x2a,0x03,0x00,0x0d,0x00,
|
||||
0x06,0x30,0x03,0x00,0x0d,0x00,0x06,0x36,0x03,0x00,0x0d,0x00,0x06,0x3c,0x03,0x00,
|
||||
0x0d,0x00,0x06,0x42,0x03,0x00,0x0d,0x00,0x06,0x48,0x03,0x00,0x0d,0x00,0x06,0x4e,
|
||||
0x03,0x00,0x0d,0x00,0x06,0x54,0x03,0x00,0x0d,0x00,0x06,0x5a,0x03,0x00,0x0d,0x00,
|
||||
0x06,0x60,0x03,0x00,0x0d,0x00,0x06,0x66,0x03,0x00,0x0d,0x00,0x06,0x6c,0x03,0x00,
|
||||
0x0d,0x00,0x06,0x72,0x03,0x00,0x0d,0x00,0x06,0x78,0x03,0x00,0x0d,0x00,0x06,0x7e,
|
||||
0x03,0x00,0x0d,0x00,0x06,0x84,0x03,0x00,0x0d,0x00,0x06,0x8a,0x03,0x00,0x0d,0x00,
|
||||
0x06,0x90,0x03,0x00,0x0d,0x00,0x06,0x96,0x03,0x00,0x0d,0x00,0x06,0x9c,0x03,0x00,
|
||||
0x0d,0x00,0x06,0xa2,0x03,0x00,0x0d,0x00,0x06,0xa8,0x03,0x00,0x0d,0x00,0x00,0xae,
|
||||
0x03,0x00,0x0d,0x00,0x00,0xb4,0x03,0x00,0x0d,0x00,0x00,0xba,0x03,0x00,0x0d,0x00,
|
||||
0x00,0xc0,0x03,0x01,0x0c,0x00,0x06,0xc6,0x03,0x02,0x0b,0x00,0x06,0xcc,0x03,0x03,
|
||||
0x0c,0x00,0x06,0xd2,0x03,0x04,0x0c,0x00,0x06,0xd8,0x03,0x03,0x0b,0x00,0x06,0xde,
|
||||
0x03,0x02,0x0b,0x00,0x06,0xe4,0x03,0x02,0x0b,0x00,0x06,0xea,0x03,0x01,0x0c,0x00,
|
||||
0x06,0xf0,0x03,0x03,0x04,0x00,0x06,0xf6,0x03,0x02,0x0b,0x00,0x06,0xfc,0x03,0x01,
|
||||
0x09,0x00,0x06,0x02,0x04,0x03,0x0c,0x00,0x06,0x08,0x04,0x05,0x09,0x00,0x06,0x0e,
|
||||
0x04,0x06,0x08,0x00,0x06,0x14,0x04,0x02,0x0b,0x00,0x06,0x1a,0x04,0x01,0x02,0x00,
|
||||
0x06,0x20,0x04,0x01,0x06,0x00,0x06,0x26,0x04,0x04,0x0a,0x00,0x06,0x2c,0x04,0x01,
|
||||
0x06,0x00,0x06,0x32,0x04,0x01,0x06,0x00,0x06,0x38,0x04,0x00,0x03,0x00,0x06,0x3e,
|
||||
0x04,0x05,0x0c,0x00,0x06,0x44,0x04,0x02,0x0b,0x00,0x06,0x4a,0x04,0x06,0x08,0x00,
|
||||
0x06,0x50,0x04,0x0a,0x0d,0x00,0x06,0x56,0x04,0x01,0x06,0x00,0x06,0x5c,0x04,0x01,
|
||||
0x07,0x00,0x06,0x62,0x04,0x03,0x0c,0x00,0x06,0x68,0x04,0x00,0x0b,0x00,0x06,0x6e,
|
||||
0x04,0x00,0x0b,0x00,0x06,0x74,0x04,0x00,0x0b,0x00,0x06,0x7a,0x04,0x02,0x0b,0x00,
|
||||
0x06,0x80,0x04,0x00,0x0b,0x00,0x06,0x86,0x04,0x00,0x0b,0x00,0x06,0x8c,0x04,0x00,
|
||||
0x0b,0x00,0x06,0x92,0x04,0x00,0x0b,0x00,0x06,0x98,0x04,0x01,0x0b,0x00,0x06,0x9e,
|
||||
0x04,0x01,0x0b,0x00,0x06,0xa4,0x04,0x03,0x0b,0x00,0x06,0xaa,0x04,0x02,0x0d,0x00,
|
||||
0x06,0xb0,0x04,0x00,0x0b,0x00,0x06,0xb6,0x04,0x00,0x0b,0x00,0x06,0xbc,0x04,0x00,
|
||||
0x0b,0x00,0x06,0xc2,0x04,0x01,0x0b,0x00,0x06,0xc8,0x04,0x00,0x0b,0x00,0x06,0xce,
|
||||
0x04,0x00,0x0b,0x00,0x06,0xd4,0x04,0x00,0x0b,0x00,0x06,0xda,0x04,0x01,0x0b,0x00,
|
||||
0x06,0xe0,0x04,0x02,0x0b,0x00,0x06,0xe6,0x04,0x00,0x0b,0x00,0x06,0xec,0x04,0x00,
|
||||
0x0b,0x00,0x06,0xf2,0x04,0x00,0x0b,0x00,0x06,0xf8,0x04,0x00,0x0b,0x00,0x06,0xfe,
|
||||
0x04,0x00,0x0b,0x00,0x06,0x04,0x05,0x01,0x0b,0x00,0x06,0x0a,0x05,0x05,0x0b,0x00,
|
||||
0x06,0x10,0x05,0x01,0x0c,0x00,0x06,0x16,0x05,0x00,0x0b,0x00,0x06,0x1c,0x05,0x00,
|
||||
0x0b,0x00,0x06,0x22,0x05,0x00,0x0b,0x00,0x06,0x28,0x05,0x01,0x0b,0x00,0x06,0x2e,
|
||||
0x05,0x00,0x0b,0x00,0x06,0x34,0x05,0x01,0x0b,0x00,0x06,0x3a,0x05,0x01,0x0c,0x00,
|
||||
0x06,0x40,0x05,0x02,0x0b,0x00,0x06,0x46,0x05,0x02,0x0b,0x00,0x06,0x4c,0x05,0x01,
|
||||
0x0b,0x00,0x06,0x52,0x05,0x02,0x0b,0x00,0x06,0x58,0x05,0x03,0x0b,0x00,0x06,0x5e,
|
||||
0x05,0x03,0x0b,0x00,0x06,0x64,0x05,0x05,0x0b,0x00,0x06,0x6a,0x05,0x05,0x0d,0x00,
|
||||
0x06,0x70,0x05,0x02,0x0b,0x00,0x06,0x76,0x05,0x02,0x0b,0x00,0x06,0x7c,0x05,0x01,
|
||||
0x0b,0x00,0x06,0x82,0x05,0x03,0x0b,0x00,0x06,0x88,0x05,0x02,0x0b,0x00,0x06,0x8e,
|
||||
0x05,0x02,0x0b,0x00,0x06,0x94,0x05,0x01,0x0b,0x00,0x06,0x9a,0x05,0x03,0x0b,0x00,
|
||||
0x06,0xa0,0x05,0x02,0x0b,0x00,0x06,0xa6,0x05,0x02,0x0b,0x00,0x06,0xac,0x05,0x02,
|
||||
0x0b,0x00,0x06,0xb2,0x05,0x02,0x0b,0x00,0x06,0xb8,0x05,0x01,0x0b,0x00,0x06,0xbe,
|
||||
0x05,0x02,0x0b,0x00,0x06,0xc4,0x05,0x03,0x0b,0x00,0x06,0xca,0x05,0x03,0x0b,0x00,
|
||||
0x06,0xd0,0x05,0x04,0x0c,0x00,0x06,0xd6,0x05,0x02,0x0b,0x00,0x06,0xdc,0x05,0x02,
|
||||
0x0b,0x00,0x06,0xe2,0x05,0x01,0x0b,0x00,0x06,0xe8,0x05,0x03,0x0b,0x00,0x06,0xee,
|
||||
0x05,0x02,0x0d,0x00,0x06,0xf4,0x05,0x01,0x0d,0x00,0x06,0xfa,0x05,0x03,0x0d,0x00,
|
||||
0x06,0x00,0x06,0x00,0x00,0x00,0x00,
|
||||
|
||||
|
||||
};
|
||||
|
||||
int sizeofdefont = sizeof defontdata;
|
||||
|
||||
void
|
||||
_unpackinfo(Fontchar *fc, uchar *p, int n)
|
||||
{
|
||||
int j;
|
||||
|
||||
for(j=0; j<=n; j++){
|
||||
fc->x = p[0]|(p[1]<<8);
|
||||
fc->top = p[2];
|
||||
fc->bottom = p[3];
|
||||
fc->left = p[4];
|
||||
fc->width = p[5];
|
||||
fc++;
|
||||
p += 6;
|
||||
}
|
||||
}
|
|
@ -1,594 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "../port/error.h"
|
||||
#include "../port/netif.h"
|
||||
|
||||
#include "etherif.h"
|
||||
|
||||
static volatile Ether *etherxx[MaxEther];
|
||||
|
||||
static struct {
|
||||
char* type;
|
||||
int (*reset)(Ether*);
|
||||
} cards[MaxEther+1];
|
||||
|
||||
void
|
||||
addethercard(char* t, int (*r)(Ether*))
|
||||
{
|
||||
static int ncard;
|
||||
|
||||
if(ncard == MaxEther)
|
||||
panic("too many ether cards");
|
||||
cards[ncard].type = t;
|
||||
cards[ncard].reset = r;
|
||||
ncard++;
|
||||
}
|
||||
|
||||
void
|
||||
etherpower(int on)
|
||||
{
|
||||
int i;
|
||||
Ether *ether;
|
||||
/* Power all ether cards on or off */
|
||||
|
||||
iprint("etherpower %d\n", on);
|
||||
for (i = 0; i < MaxEther; i++){
|
||||
if ((ether = etherxx[i]) == nil)
|
||||
continue;
|
||||
if(on){
|
||||
if (ether->writer == 0){
|
||||
print("etherpower: already powered up\n");
|
||||
continue;
|
||||
}
|
||||
if (ether->power)
|
||||
ether->power(ether, on);
|
||||
wunlock(ether);
|
||||
/* Unlock when power restored */
|
||||
}else{
|
||||
if (ether->writer != 0){
|
||||
print("etherpower: already powered down\n");
|
||||
continue;
|
||||
}
|
||||
/* Keep locked until power goes back on */
|
||||
wlock(ether);
|
||||
if (ether->power)
|
||||
ether->power(ether, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
etherconfig(int on, char *spec, DevConf *cf)
|
||||
{
|
||||
Ether *ether;
|
||||
int n, ctlrno;
|
||||
char name[32], buf[128];
|
||||
char *p, *e;
|
||||
|
||||
ctlrno = atoi(spec);
|
||||
sprint(name, "ether%d", ctlrno);
|
||||
|
||||
if(on == 0)
|
||||
return -1;
|
||||
|
||||
if(etherxx[ctlrno] != nil)
|
||||
return -1;
|
||||
|
||||
ether = malloc(sizeof(Ether));
|
||||
if(ether == nil)
|
||||
panic("etherconfig");
|
||||
ether->DevConf = *cf;
|
||||
|
||||
for(n = 0; cards[n].type; n++){
|
||||
if(strcmp(cards[n].type, ether->type) != 0)
|
||||
continue;
|
||||
if(cards[n].reset(ether))
|
||||
break;
|
||||
|
||||
if(ether->mbps >= 100){
|
||||
netifinit(ether, name, Ntypes, 256*1024);
|
||||
if(ether->oq == 0)
|
||||
ether->oq = qopen(256*1024, Qmsg, 0, 0);
|
||||
}
|
||||
else{
|
||||
netifinit(ether, name, Ntypes, 65*1024);
|
||||
if(ether->oq == 0)
|
||||
ether->oq = qopen(65*1024, Qmsg, 0, 0);
|
||||
}
|
||||
if(ether->oq == 0)
|
||||
panic("etherreset %s", name);
|
||||
ether->alen = Eaddrlen;
|
||||
memmove(ether->addr, ether->ea, Eaddrlen);
|
||||
memset(ether->bcast, 0xFF, Eaddrlen);
|
||||
ether->mbps = 10;
|
||||
ether->minmtu = ETHERMINTU;
|
||||
ether->maxmtu = ETHERMAXTU;
|
||||
|
||||
if(ether->interrupt != nil)
|
||||
intrenable(cf->itype, cf->intnum, ether->interrupt, ether, name);
|
||||
|
||||
p = buf;
|
||||
e = buf+sizeof(buf);
|
||||
p = seprint(p, e, "#l%d: %s: %dMbps port 0x%luX",
|
||||
ctlrno, ether->type, ether->mbps, ether->ports[0].port);
|
||||
if(ether->mem)
|
||||
p = seprint(p, e, " addr 0x%luX", PADDR(ether->mem));
|
||||
if(ether->ports[0].size)
|
||||
p = seprint(p, e, " size 0x%X", ether->ports[0].size);
|
||||
p = seprint(p, e, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
|
||||
ether->ea[0], ether->ea[1], ether->ea[2],
|
||||
ether->ea[3], ether->ea[4], ether->ea[5]);
|
||||
seprint(p, e, "\n");
|
||||
print("%s", buf);
|
||||
|
||||
etherxx[ctlrno] = ether;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ether->type)
|
||||
free(ether->type);
|
||||
free(ether);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Chan*
|
||||
etherattach(char* spec)
|
||||
{
|
||||
ulong ctlrno;
|
||||
char *p;
|
||||
Chan *chan;
|
||||
Ether *ether;
|
||||
|
||||
ctlrno = 0;
|
||||
if(spec && *spec){
|
||||
ctlrno = strtoul(spec, &p, 0);
|
||||
if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
|
||||
error(Ebadarg);
|
||||
}
|
||||
if((ether = etherxx[ctlrno]) == 0)
|
||||
error(Enodev);
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
chan = devattach('l', spec);
|
||||
chan->dev = ctlrno;
|
||||
if(ether->attach)
|
||||
ether->attach(ether);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return chan;
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
|
||||
{
|
||||
Walkqid *q;
|
||||
Ether *ether;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
q = netifwalk(ether, chan, nchan, name, nname);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return q;
|
||||
}
|
||||
|
||||
static int
|
||||
etherstat(Chan* chan, uchar* dp, int n)
|
||||
{
|
||||
int s;
|
||||
Ether *ether;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
s = netifstat(ether, chan, dp, n);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return s;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
etheropen(Chan* chan, int omode)
|
||||
{
|
||||
Chan *c;
|
||||
Ether *ether;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
c = netifopen(ether, chan, omode);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
ethercreate(Chan*, char*, int, ulong)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
etherclose(Chan* chan)
|
||||
{
|
||||
Ether *ether;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
netifclose(ether, chan);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
}
|
||||
|
||||
static long
|
||||
etherread(Chan* chan, void* buf, long n, vlong off)
|
||||
{
|
||||
Ether *ether;
|
||||
ulong offset = off;
|
||||
long r;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
|
||||
/*
|
||||
* With some controllers it is necessary to reach
|
||||
* into the chip to extract statistics.
|
||||
*/
|
||||
if(NETTYPE(chan->qid.path) == Nifstatqid){
|
||||
r = ether->ifstat(ether, buf, n, offset);
|
||||
goto out;
|
||||
}
|
||||
if(NETTYPE(chan->qid.path) == Nstatqid)
|
||||
ether->ifstat(ether, buf, 0, offset);
|
||||
}
|
||||
r = netifread(ether, chan, buf, n, offset);
|
||||
out:
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return r;
|
||||
}
|
||||
|
||||
static Block*
|
||||
etherbread(Chan* chan, long n, ulong offset)
|
||||
{
|
||||
Block *b;
|
||||
Ether *ether;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
b = netifbread(ether, chan, n, offset);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return b;
|
||||
}
|
||||
|
||||
static int
|
||||
etherwstat(Chan* chan, uchar* dp, int n)
|
||||
{
|
||||
Ether *ether;
|
||||
int r;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
r = netifwstat(ether, chan, dp, n);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
|
||||
{
|
||||
int i, n;
|
||||
Block *bp;
|
||||
|
||||
if(qwindow(f->in) <= 0)
|
||||
return;
|
||||
if(len > 58)
|
||||
n = 58;
|
||||
else
|
||||
n = len;
|
||||
bp = iallocb(64);
|
||||
if(bp == nil)
|
||||
return;
|
||||
memmove(bp->wp, pkt->d, n);
|
||||
i = TK2MS(MACHP(0)->ticks);
|
||||
bp->wp[58] = len>>8;
|
||||
bp->wp[59] = len;
|
||||
bp->wp[60] = i>>24;
|
||||
bp->wp[61] = i>>16;
|
||||
bp->wp[62] = i>>8;
|
||||
bp->wp[63] = i;
|
||||
bp->wp += 64;
|
||||
qpass(f->in, bp);
|
||||
}
|
||||
|
||||
Block*
|
||||
etheriq(Ether* ether, Block* bp, int fromwire)
|
||||
{
|
||||
Etherpkt *pkt;
|
||||
ushort type;
|
||||
int len, multi, tome, fromme;
|
||||
Netfile **ep, *f, **fp, *fx;
|
||||
Block *xbp;
|
||||
|
||||
ether->inpackets++;
|
||||
|
||||
pkt = (Etherpkt*)bp->rp;
|
||||
len = BLEN(bp);
|
||||
type = (pkt->type[0]<<8)|pkt->type[1];
|
||||
fx = 0;
|
||||
ep = ðer->f[Ntypes];
|
||||
|
||||
multi = pkt->d[0] & 1;
|
||||
/* check for valid multicast addresses */
|
||||
if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
|
||||
if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
|
||||
if(fromwire){
|
||||
freeb(bp);
|
||||
bp = 0;
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
|
||||
/* is it for me? */
|
||||
tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
|
||||
fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
|
||||
|
||||
/*
|
||||
* Multiplex the packet to all the connections which want it.
|
||||
* If the packet is not to be used subsequently (fromwire != 0),
|
||||
* attempt to simply pass it into one of the connections, thereby
|
||||
* saving a copy of the data (usual case hopefully).
|
||||
*/
|
||||
for(fp = ether->f; fp < ep; fp++){
|
||||
if(f = *fp)
|
||||
if(f->type == type || f->type < 0)
|
||||
if(tome || multi || f->prom){
|
||||
/* Don't want to hear bridged packets */
|
||||
if(f->bridge && !fromwire && !fromme)
|
||||
continue;
|
||||
if(!f->headersonly){
|
||||
if(fromwire && fx == 0)
|
||||
fx = f;
|
||||
else if(xbp = iallocb(len)){
|
||||
memmove(xbp->wp, pkt, len);
|
||||
xbp->wp += len;
|
||||
qpass(f->in, xbp);
|
||||
}
|
||||
else
|
||||
ether->soverflows++;
|
||||
}
|
||||
else
|
||||
etherrtrace(f, pkt, len);
|
||||
}
|
||||
}
|
||||
|
||||
if(fx){
|
||||
if(qpass(fx->in, bp) < 0)
|
||||
ether->soverflows++;
|
||||
return 0;
|
||||
}
|
||||
if(fromwire){
|
||||
freeb(bp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
static int
|
||||
etheroq(Ether* ether, Block* bp)
|
||||
{
|
||||
int len, loopback;
|
||||
Etherpkt *pkt;
|
||||
|
||||
ether->outpackets++;
|
||||
|
||||
/*
|
||||
* Check if the packet has to be placed back onto the input queue,
|
||||
* i.e. if it's a loopback or broadcast packet or the interface is
|
||||
* in promiscuous mode.
|
||||
* If it's a loopback packet indicate to etheriq that the data isn't
|
||||
* needed and return, etheriq will pass-on or free the block.
|
||||
* To enable bridging to work, only packets that were originated
|
||||
* by this interface are fed back.
|
||||
*/
|
||||
pkt = (Etherpkt*)bp->rp;
|
||||
len = BLEN(bp);
|
||||
loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
|
||||
if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
|
||||
if(etheriq(ether, bp, loopback) == 0)
|
||||
return len;
|
||||
|
||||
qbwrite(ether->oq, bp);
|
||||
if(ether->transmit != nil)
|
||||
ether->transmit(ether);
|
||||
return len;
|
||||
}
|
||||
|
||||
static long
|
||||
etherwrite(Chan* chan, void* buf, long n, vlong)
|
||||
{
|
||||
Ether *ether;
|
||||
Block *bp;
|
||||
long l;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
if(NETTYPE(chan->qid.path) != Ndataqid) {
|
||||
l = netifwrite(ether, chan, buf, n);
|
||||
if(l >= 0)
|
||||
goto out;
|
||||
if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
|
||||
qnoblock(ether->oq, 1);
|
||||
goto out;
|
||||
}
|
||||
if(ether->ctl!=nil){
|
||||
l = ether->ctl(ether,buf,n);
|
||||
goto out;
|
||||
}
|
||||
error(Ebadctl);
|
||||
}
|
||||
|
||||
if(n > ether->maxmtu)
|
||||
error(Etoobig);
|
||||
if(n < ether->minmtu)
|
||||
error(Etoosmall);
|
||||
bp = allocb(n);
|
||||
memmove(bp->rp, buf, n);
|
||||
memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
|
||||
bp->wp += n;
|
||||
|
||||
l = etheroq(ether, bp);
|
||||
out:
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return l;
|
||||
}
|
||||
|
||||
static long
|
||||
etherbwrite(Chan* chan, Block* bp, ulong)
|
||||
{
|
||||
Ether *ether;
|
||||
long n;
|
||||
|
||||
n = BLEN(bp);
|
||||
if(NETTYPE(chan->qid.path) != Ndataqid){
|
||||
if(waserror()) {
|
||||
freeb(bp);
|
||||
nexterror();
|
||||
}
|
||||
n = etherwrite(chan, bp->rp, n, 0);
|
||||
poperror();
|
||||
freeb(bp);
|
||||
return n;
|
||||
}
|
||||
ether = etherxx[chan->dev];
|
||||
rlock(ether);
|
||||
if(waserror()) {
|
||||
runlock(ether);
|
||||
nexterror();
|
||||
}
|
||||
if(n > ether->maxmtu){
|
||||
freeb(bp);
|
||||
error(Etoobig);
|
||||
}
|
||||
if(n < ether->minmtu){
|
||||
freeb(bp);
|
||||
error(Etoosmall);
|
||||
}
|
||||
n = etheroq(ether, bp);
|
||||
poperror();
|
||||
runlock(ether);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
parseether(uchar *to, char *from)
|
||||
{
|
||||
char nip[4];
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
p = from;
|
||||
for(i = 0; i < 6; i++){
|
||||
if(*p == 0)
|
||||
return -1;
|
||||
nip[0] = *p++;
|
||||
if(*p == 0)
|
||||
return -1;
|
||||
nip[1] = *p++;
|
||||
nip[2] = 0;
|
||||
to[i] = strtoul(nip, 0, 16);
|
||||
if(*p == ':')
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
etherreset(void)
|
||||
{
|
||||
}
|
||||
|
||||
#define POLY 0xedb88320
|
||||
|
||||
/* really slow 32 bit crc for ethers */
|
||||
ulong
|
||||
ethercrc(uchar *p, int len)
|
||||
{
|
||||
int i, j;
|
||||
ulong crc, b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for(i = 0; i < len; i++){
|
||||
b = *p++;
|
||||
for(j = 0; j < 8; j++){
|
||||
crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
|
||||
b >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
Dev etherdevtab = {
|
||||
'l',
|
||||
"ether",
|
||||
|
||||
etherreset,
|
||||
devinit,
|
||||
devshutdown,
|
||||
etherattach,
|
||||
etherwalk,
|
||||
etherstat,
|
||||
etheropen,
|
||||
ethercreate,
|
||||
etherclose,
|
||||
etherread,
|
||||
etherbread,
|
||||
etherwrite,
|
||||
etherbwrite,
|
||||
devremove,
|
||||
etherwstat,
|
||||
etherpower,
|
||||
etherconfig,
|
||||
};
|
|
@ -1,876 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
/*
|
||||
* on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit
|
||||
* accesses, one to the low half of the chip and the other to the high
|
||||
* half. Therefore for all command accesses, ushort indices in the
|
||||
* manuals turn into ulong indices in our code. Also, by copying all
|
||||
* 16 bit commands to both halves of a 32 bit command, we erase 2
|
||||
* sectors for each request erase request.
|
||||
*/
|
||||
|
||||
#define mirror(x) (((x)<<16)|(x))
|
||||
|
||||
/* this defines a contiguous set of erase blocks of one size */
|
||||
typedef struct FlashRegion FlashRegion;
|
||||
struct FlashRegion
|
||||
{
|
||||
ulong addr; /* start of region */
|
||||
ulong end; /* end of region + 1 */
|
||||
ulong n; /* number of blocks */
|
||||
ulong size; /* size of each block */
|
||||
};
|
||||
|
||||
/* this defines a particular access algorithm */
|
||||
typedef struct FlashAlg FlashAlg;
|
||||
struct FlashAlg
|
||||
{
|
||||
int id;
|
||||
char *name;
|
||||
void (*identify)(void); /* identify device */
|
||||
void (*erase)(ulong); /* erase a region */
|
||||
void (*write)(void*, long, ulong); /* write a region */
|
||||
};
|
||||
|
||||
static void ise_id(void);
|
||||
static void ise_erase(ulong);
|
||||
static void ise_write(void*, long, ulong);
|
||||
|
||||
static void afs_id(void);
|
||||
static void afs_erase(ulong);
|
||||
static void afs_write(void*, long, ulong);
|
||||
|
||||
static ulong blockstart(ulong);
|
||||
static ulong blockend(ulong);
|
||||
|
||||
FlashAlg falg[] =
|
||||
{
|
||||
{ 1, "Intel/Sharp Extended", ise_id, ise_erase, ise_write },
|
||||
{ 2, "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write },
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
RWlock;
|
||||
ulong *p;
|
||||
ushort algid; /* access algorithm */
|
||||
FlashAlg *alg;
|
||||
ushort manid; /* manufacturer id */
|
||||
ushort devid; /* device id */
|
||||
ulong size; /* size in bytes */
|
||||
int wbsize; /* size of write buffer */
|
||||
ulong nr; /* number of regions */
|
||||
uchar bootprotect;
|
||||
FlashRegion r[32];
|
||||
} flash;
|
||||
|
||||
enum
|
||||
{
|
||||
Maxwchunk= 1024, /* maximum chunk written by one call to falg->write */
|
||||
};
|
||||
|
||||
/*
|
||||
* common flash interface
|
||||
*/
|
||||
static uchar
|
||||
cfigetc(int off)
|
||||
{
|
||||
uchar rv;
|
||||
|
||||
flash.p[0x55] = mirror(0x98);
|
||||
rv = flash.p[off];
|
||||
flash.p[0x55] = mirror(0xFF);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static ushort
|
||||
cfigets(int off)
|
||||
{
|
||||
return (cfigetc(off+1)<<8)|cfigetc(off);
|
||||
}
|
||||
|
||||
static ulong
|
||||
cfigetl(int off)
|
||||
{
|
||||
return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)|
|
||||
(cfigetc(off+1)<<8)|cfigetc(off);
|
||||
}
|
||||
|
||||
static void
|
||||
cfiquery(void)
|
||||
{
|
||||
uchar q, r, y;
|
||||
ulong x, addr;
|
||||
|
||||
q = cfigetc(0x10);
|
||||
r = cfigetc(0x11);
|
||||
y = cfigetc(0x12);
|
||||
if(q != 'Q' || r != 'R' || y != 'Y'){
|
||||
print("cfi query failed: %ux %ux %ux\n", q, r, y);
|
||||
return;
|
||||
}
|
||||
flash.algid = cfigetc(0x13);
|
||||
flash.size = 1<<(cfigetc(0x27)+1);
|
||||
flash.wbsize = 1<<(cfigetc(0x2a)+1);
|
||||
flash.nr = cfigetc(0x2c);
|
||||
if(flash.nr > nelem(flash.r)){
|
||||
print("cfi reports > %d regions\n", nelem(flash.r));
|
||||
flash.nr = nelem(flash.r);
|
||||
}
|
||||
addr = 0;
|
||||
for(q = 0; q < flash.nr; q++){
|
||||
x = cfigetl(q+0x2d);
|
||||
flash.r[q].size = 2*256*(x>>16);
|
||||
flash.r[q].n = (x&0xffff)+1;
|
||||
flash.r[q].addr = addr;
|
||||
addr += flash.r[q].size*flash.r[q].n;
|
||||
flash.r[q].end = addr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* flash device interface
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
Qtopdir,
|
||||
Q2nddir,
|
||||
Qfctl,
|
||||
Qfdata,
|
||||
|
||||
Maxpart= 8,
|
||||
};
|
||||
|
||||
|
||||
typedef struct FPart FPart;
|
||||
struct FPart
|
||||
{
|
||||
char *name;
|
||||
char *ctlname;
|
||||
ulong start;
|
||||
ulong end;
|
||||
};
|
||||
static FPart part[Maxpart];
|
||||
|
||||
#define FQID(p,q) ((p)<<8|(q))
|
||||
#define FTYPE(q) ((q) & 0xff)
|
||||
#define FPART(q) (&part[(q) >>8])
|
||||
|
||||
static int
|
||||
gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
|
||||
{
|
||||
Qid q;
|
||||
FPart *fp;
|
||||
|
||||
q.vers = 0;
|
||||
|
||||
/* top level directory contains the name of the network */
|
||||
if(c->qid.path == Qtopdir){
|
||||
switch(i){
|
||||
case DEVDOTDOT:
|
||||
q.path = Qtopdir;
|
||||
q.type = QTDIR;
|
||||
devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
|
||||
break;
|
||||
case 0:
|
||||
q.path = Q2nddir;
|
||||
q.type = QTDIR;
|
||||
devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* second level contains all partitions and their control files */
|
||||
switch(i) {
|
||||
case DEVDOTDOT:
|
||||
q.path = Qtopdir;
|
||||
q.type = QTDIR;
|
||||
devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
|
||||
break;
|
||||
default:
|
||||
if(i >= 2*Maxpart)
|
||||
return -1;
|
||||
fp = &part[i>>1];
|
||||
if(fp->name == nil)
|
||||
return 0;
|
||||
if(i & 1){
|
||||
q.path = FQID(i>>1, Qfdata);
|
||||
q.type = QTFILE;
|
||||
devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
|
||||
} else {
|
||||
q.path = FQID(i>>1, Qfctl);
|
||||
q.type = QTFILE;
|
||||
devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static FPart*
|
||||
findpart(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < Maxpart; i++)
|
||||
if(part[i].name != nil && strcmp(name, part[i].name) == 0)
|
||||
break;
|
||||
if(i >= Maxpart)
|
||||
return nil;
|
||||
return &part[i];
|
||||
}
|
||||
|
||||
static void
|
||||
addpart(FPart *fp, char *name, ulong start, ulong end)
|
||||
{
|
||||
int i;
|
||||
char ctlname[64];
|
||||
|
||||
if(fp == nil){
|
||||
if(start >= flash.size || end > flash.size)
|
||||
error(Ebadarg);
|
||||
} else {
|
||||
start += fp->start;
|
||||
end += fp->start;
|
||||
if(start >= fp->end || end > fp->end)
|
||||
error(Ebadarg);
|
||||
}
|
||||
if(blockstart(start) != start)
|
||||
error("must start on erase boundary");
|
||||
if(blockstart(end) != end && end != flash.size)
|
||||
error("must end on erase boundary");
|
||||
|
||||
fp = findpart(name);
|
||||
if(fp != nil)
|
||||
error(Eexist);
|
||||
for(i = 0; i < Maxpart; i++)
|
||||
if(part[i].name == nil)
|
||||
break;
|
||||
if(i == Maxpart)
|
||||
error("no more partitions");
|
||||
fp = &part[i];
|
||||
kstrdup(&fp->name, name);
|
||||
snprint(ctlname, sizeof ctlname, "%sctl", name);
|
||||
kstrdup(&fp->ctlname, ctlname);
|
||||
fp->start = start;
|
||||
fp->end = end;
|
||||
}
|
||||
|
||||
static void
|
||||
rempart(FPart *fp)
|
||||
{
|
||||
char *p, *cp;
|
||||
|
||||
p = fp->name;
|
||||
fp->name = nil;
|
||||
cp = fp->ctlname;
|
||||
fp->ctlname = nil;
|
||||
free(p);
|
||||
free(cp);
|
||||
}
|
||||
|
||||
void
|
||||
flashinit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
flash.p = (ulong*)FLASHZERO;
|
||||
cfiquery();
|
||||
for(i = 0; i < nelem(falg); i++)
|
||||
if(flash.algid == falg[i].id){
|
||||
flash.alg = &falg[i];
|
||||
(*flash.alg->identify)();
|
||||
break;
|
||||
}
|
||||
flash.bootprotect = 1;
|
||||
|
||||
addpart(nil, "flash", 0, flash.size);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
flashattach(char* spec)
|
||||
{
|
||||
return devattach('F', spec);
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
flashwalk(Chan *c, Chan *nc, char **name, int nname)
|
||||
{
|
||||
return devwalk(c, nc, name, nname, nil, 0, gen);
|
||||
}
|
||||
|
||||
static int
|
||||
flashstat(Chan *c, uchar *db, int n)
|
||||
{
|
||||
return devstat(c, db, n, nil, 0, gen);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
flashopen(Chan* c, int omode)
|
||||
{
|
||||
omode = openmode(omode);
|
||||
if(strcmp(up->user, eve)!=0)
|
||||
error(Eperm);
|
||||
return devopen(c, omode, nil, 0, gen);
|
||||
}
|
||||
|
||||
static void
|
||||
flashclose(Chan*)
|
||||
{
|
||||
}
|
||||
|
||||
static long
|
||||
flashctlread(FPart *fp, void* a, long n, vlong off)
|
||||
{
|
||||
char *buf, *p, *e;
|
||||
int i;
|
||||
ulong addr, end;
|
||||
|
||||
buf = smalloc(1024);
|
||||
e = buf + 1024;
|
||||
p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start,
|
||||
flash.wbsize, flash.manid, flash.devid);
|
||||
addr = fp->start;
|
||||
for(i = 0; i < flash.nr && addr < fp->end; i++)
|
||||
if(flash.r[i].addr <= addr && flash.r[i].end > addr){
|
||||
if(fp->end <= flash.r[i].end)
|
||||
end = fp->end;
|
||||
else
|
||||
end = flash.r[i].end;
|
||||
p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
|
||||
(end-addr)/flash.r[i].size, flash.r[i].size);
|
||||
addr = end;
|
||||
}
|
||||
n = readstr(off, a, n, buf);
|
||||
free(buf);
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
flashdataread(FPart *fp, void* a, long n, vlong off)
|
||||
{
|
||||
rlock(&flash);
|
||||
if(waserror()){
|
||||
runlock(&flash);
|
||||
nexterror();
|
||||
}
|
||||
if(fp->name == nil)
|
||||
error("partition vanished");
|
||||
if(!iseve())
|
||||
error(Eperm);
|
||||
off += fp->start;
|
||||
if(off >= fp->end)
|
||||
n = 0;
|
||||
if(off+n >= fp->end)
|
||||
n = fp->end - off;
|
||||
if(n > 0)
|
||||
memmove(a, ((uchar*)FLASHZERO)+off, n);
|
||||
runlock(&flash);
|
||||
poperror();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
flashread(Chan* c, void* a, long n, vlong off)
|
||||
{
|
||||
int t;
|
||||
|
||||
if(c->qid.type == QTDIR)
|
||||
return devdirread(c, a, n, nil, 0, gen);
|
||||
t = FTYPE(c->qid.path);
|
||||
switch(t){
|
||||
default:
|
||||
error(Eperm);
|
||||
case Qfctl:
|
||||
n = flashctlread(FPART(c->qid.path), a, n, off);
|
||||
break;
|
||||
case Qfdata:
|
||||
n = flashdataread(FPART(c->qid.path), a, n, off);
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
bootprotect(ulong addr)
|
||||
{
|
||||
FlashRegion *r;
|
||||
|
||||
if(flash.bootprotect == 0)
|
||||
return;
|
||||
if(flash.nr == 0)
|
||||
error("writing over boot loader disallowed");
|
||||
r = flash.r;
|
||||
if(addr >= r->addr && addr < r->addr + r->size)
|
||||
error("writing over boot loader disallowed");
|
||||
}
|
||||
|
||||
static ulong
|
||||
blockstart(ulong addr)
|
||||
{
|
||||
FlashRegion *r, *e;
|
||||
ulong x;
|
||||
|
||||
r = flash.r;
|
||||
for(e = &flash.r[flash.nr]; r < e; r++)
|
||||
if(addr >= r->addr && addr < r->end){
|
||||
x = addr - r->addr;
|
||||
x /= r->size;
|
||||
return r->addr + x*r->size;
|
||||
}
|
||||
|
||||
return (ulong)-1;
|
||||
}
|
||||
|
||||
static ulong
|
||||
blockend(ulong addr)
|
||||
{
|
||||
FlashRegion *r, *e;
|
||||
ulong x;
|
||||
|
||||
r = flash.r;
|
||||
for(e = &flash.r[flash.nr]; r < e; r++)
|
||||
if(addr >= r->addr && addr < r->end){
|
||||
x = addr - r->addr;
|
||||
x /= r->size;
|
||||
return r->addr + (x+1)*r->size;
|
||||
}
|
||||
|
||||
return (ulong)-1;
|
||||
}
|
||||
|
||||
static long
|
||||
flashctlwrite(FPart *fp, char *p, long n)
|
||||
{
|
||||
Cmdbuf *cmd;
|
||||
ulong off;
|
||||
|
||||
if(fp == nil)
|
||||
panic("flashctlwrite");
|
||||
|
||||
cmd = parsecmd(p, n);
|
||||
wlock(&flash);
|
||||
if(waserror()){
|
||||
wunlock(&flash);
|
||||
nexterror();
|
||||
}
|
||||
if(strcmp(cmd->f[0], "erase") == 0){
|
||||
switch(cmd->nf){
|
||||
case 2:
|
||||
/* erase a single block in the partition */
|
||||
off = atoi(cmd->f[1]);
|
||||
off += fp->start;
|
||||
if(off >= fp->end)
|
||||
error("region not in partition");
|
||||
if(off != blockstart(off))
|
||||
error("erase must be a block boundary");
|
||||
bootprotect(off);
|
||||
(*flash.alg->erase)(off);
|
||||
break;
|
||||
case 1:
|
||||
/* erase the whole partition */
|
||||
bootprotect(fp->start);
|
||||
for(off = fp->start; off < fp->end; off = blockend(off))
|
||||
(*flash.alg->erase)(off);
|
||||
break;
|
||||
default:
|
||||
error(Ebadarg);
|
||||
}
|
||||
} else if(strcmp(cmd->f[0], "add") == 0){
|
||||
if(cmd->nf != 4)
|
||||
error(Ebadarg);
|
||||
addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
|
||||
} else if(strcmp(cmd->f[0], "remove") == 0){
|
||||
rempart(fp);
|
||||
} else if(strcmp(cmd->f[0], "protectboot") == 0){
|
||||
if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
|
||||
flash.bootprotect = 1;
|
||||
else
|
||||
flash.bootprotect = 0;
|
||||
} else
|
||||
error(Ebadarg);
|
||||
poperror();
|
||||
wunlock(&flash);
|
||||
free(cmd);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
flashdatawrite(FPart *fp, uchar *p, long n, long off)
|
||||
{
|
||||
uchar *end;
|
||||
int m;
|
||||
int on;
|
||||
long ooff;
|
||||
uchar *buf;
|
||||
|
||||
if(fp == nil)
|
||||
panic("flashctlwrite");
|
||||
|
||||
buf = nil;
|
||||
wlock(&flash);
|
||||
if(waserror()){
|
||||
wunlock(&flash);
|
||||
if(buf != nil)
|
||||
free(buf);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
if(fp->name == nil)
|
||||
error("partition vanished");
|
||||
if(!iseve())
|
||||
error(Eperm);
|
||||
|
||||
/* can't cross partition boundaries */
|
||||
off += fp->start;
|
||||
if(off >= fp->end || off+n > fp->end || n <= 0)
|
||||
error(Ebadarg);
|
||||
|
||||
/* make sure we're not writing the boot sector */
|
||||
bootprotect(off);
|
||||
|
||||
on = n;
|
||||
|
||||
/*
|
||||
* get the data into kernel memory to avoid faults during writing.
|
||||
* if write is not on a quad boundary or not a multiple of 4 bytes,
|
||||
* extend with data already in flash.
|
||||
*/
|
||||
buf = smalloc(n+8);
|
||||
m = off & 3;
|
||||
if(m){
|
||||
*(ulong*)buf = flash.p[(off)>>2];
|
||||
n += m;
|
||||
off -= m;
|
||||
}
|
||||
if(n & 3){
|
||||
n -= n & 3;
|
||||
*(ulong*)(&buf[n]) = flash.p[(off+n)>>2];
|
||||
n += 4;
|
||||
}
|
||||
memmove(&buf[m], p, on);
|
||||
|
||||
/* (*flash.alg->write) can't cross blocks */
|
||||
ooff = off;
|
||||
p = buf;
|
||||
for(end = p + n; p < end; p += m){
|
||||
m = blockend(off) - off;
|
||||
if(m > end - p)
|
||||
m = end - p;
|
||||
if(m > Maxwchunk)
|
||||
m = Maxwchunk;
|
||||
(*flash.alg->write)(p, m, off);
|
||||
off += m;
|
||||
}
|
||||
|
||||
/* make sure write succeeded */
|
||||
if(memcmp(buf, &flash.p[ooff>>2], n) != 0)
|
||||
error("written bytes don't match");
|
||||
|
||||
wunlock(&flash);
|
||||
free(buf);
|
||||
poperror();
|
||||
|
||||
return on;
|
||||
}
|
||||
|
||||
static long
|
||||
flashwrite(Chan* c, void* a, long n, vlong off)
|
||||
{
|
||||
int t;
|
||||
|
||||
if(c->qid.type == QTDIR)
|
||||
error(Eperm);
|
||||
|
||||
if(!iseve())
|
||||
error(Eperm);
|
||||
|
||||
t = FTYPE(c->qid.path);
|
||||
switch(t){
|
||||
default:
|
||||
panic("flashwrite");
|
||||
case Qfctl:
|
||||
n = flashctlwrite(FPART(c->qid.path), a, n);
|
||||
break;
|
||||
case Qfdata:
|
||||
n = flashdatawrite(FPART(c->qid.path), a, n, off);
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
Dev flashdevtab = {
|
||||
'F',
|
||||
"flash",
|
||||
|
||||
devreset,
|
||||
flashinit,
|
||||
devshutdown,
|
||||
flashattach,
|
||||
flashwalk,
|
||||
flashstat,
|
||||
flashopen,
|
||||
devcreate,
|
||||
flashclose,
|
||||
flashread,
|
||||
devbread,
|
||||
flashwrite,
|
||||
devbwrite,
|
||||
devremove,
|
||||
devwstat,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/* status register */
|
||||
ISEs_lockerr= 1<<1,
|
||||
ISEs_powererr= 1<<3,
|
||||
ISEs_progerr= 1<<4,
|
||||
ISEs_eraseerr= 1<<5,
|
||||
ISEs_ready= 1<<7,
|
||||
ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
|
||||
|
||||
/* extended status register */
|
||||
ISExs_bufavail= 1<<7,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* intel/sharp extended command set */
|
||||
static void
|
||||
ise_reset(void)
|
||||
{
|
||||
flash.p[0x55] = mirror(0xff); /* reset */
|
||||
}
|
||||
static void
|
||||
ise_id(void)
|
||||
{
|
||||
ise_reset();
|
||||
flash.p[0x555] = mirror(0x90); /* uncover vendor info */
|
||||
flash.manid = flash.p[00];
|
||||
flash.devid = flash.p[01];
|
||||
ise_reset();
|
||||
}
|
||||
static void
|
||||
ise_clearerror(void)
|
||||
{
|
||||
flash.p[0x100] = mirror(0x50);
|
||||
|
||||
}
|
||||
static void
|
||||
ise_error(int bank, ulong status)
|
||||
{
|
||||
char err[64];
|
||||
|
||||
if(status & (ISEs_lockerr)){
|
||||
sprint(err, "flash%d: block locked %lux", bank, status);
|
||||
error(err);
|
||||
}
|
||||
if(status & (ISEs_powererr)){
|
||||
sprint(err, "flash%d: low prog voltage %lux", bank, status);
|
||||
error(err);
|
||||
}
|
||||
if(status & (ISEs_progerr|ISEs_eraseerr)){
|
||||
sprint(err, "flash%d: i/o error %lux", bank, status);
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
static void
|
||||
ise_erase(ulong addr)
|
||||
{
|
||||
ulong start;
|
||||
ulong x;
|
||||
|
||||
addr >>= 2; /* convert to ulong offset */
|
||||
|
||||
flashprogpower(1);
|
||||
flash.p[addr] = mirror(0x20);
|
||||
flash.p[addr] = mirror(0xd0);
|
||||
start = m->ticks;
|
||||
do {
|
||||
x = flash.p[addr];
|
||||
if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
|
||||
break;
|
||||
} while(TK2MS(m->ticks-start) < 1500);
|
||||
flashprogpower(0);
|
||||
|
||||
ise_clearerror();
|
||||
ise_error(0, x);
|
||||
ise_error(1, x>>16);
|
||||
|
||||
ise_reset();
|
||||
}
|
||||
/*
|
||||
* the flash spec claimes writing goes faster if we use
|
||||
* the write buffer. We fill the write buffer and then
|
||||
* issue the write request. After the write request,
|
||||
* subsequent reads will yield the status register.
|
||||
*
|
||||
* returns the status, even on timeouts.
|
||||
*
|
||||
* NOTE: I tried starting back to back buffered writes
|
||||
* without reading the status in between, as the
|
||||
* flowchart in the intel data sheet suggests.
|
||||
* However, it always responded with an illegal
|
||||
* command sequence, so I must be missing something.
|
||||
* If someone learns better, please email me, though
|
||||
* I doubt it will be much faster. - presotto@bell-labs.com
|
||||
*/
|
||||
static int
|
||||
ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status)
|
||||
{
|
||||
ulong x, start;
|
||||
int i;
|
||||
int s;
|
||||
|
||||
/* put flash into write buffer mode */
|
||||
start = m->ticks;
|
||||
for(;;) {
|
||||
s = splhi();
|
||||
/* request write buffer mode */
|
||||
flash.p[baddr] = mirror(0xe8);
|
||||
|
||||
/* look at extended status reg for status */
|
||||
if((flash.p[baddr] & mirror(1<<7)) == mirror(1<<7))
|
||||
break;
|
||||
splx(s);
|
||||
|
||||
/* didn't work, keep trying for 2 secs */
|
||||
if(TK2MS(m->ticks-start) > 2000){
|
||||
/* set up to read status */
|
||||
flash.p[baddr] = mirror(0x70);
|
||||
*status = flash.p[baddr];
|
||||
pprint("write buffered cmd timed out\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill write buffer */
|
||||
flash.p[baddr] = mirror(n-1);
|
||||
for(i = 0; i < n; i++)
|
||||
flash.p[off+i] = *p++;
|
||||
|
||||
/* program from buffer */
|
||||
flash.p[baddr] = mirror(0xd0);
|
||||
splx(s);
|
||||
|
||||
/* wait till the programming is done */
|
||||
start = m->ticks;
|
||||
for(;;) {
|
||||
x = *status = flash.p[baddr]; /* read status register */
|
||||
if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
|
||||
break;
|
||||
if(TK2MS(m->ticks-start) > 2000){
|
||||
pprint("read status timed out\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(x & mirror(ISEs_err))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
}
|
||||
static void
|
||||
ise_write(void *a, long n, ulong off)
|
||||
{
|
||||
ulong *p, *end;
|
||||
int i, wbsize;
|
||||
ulong x, baddr;
|
||||
|
||||
/* everything in terms of ulongs */
|
||||
wbsize = flash.wbsize>>2;
|
||||
baddr = blockstart(off);
|
||||
off >>= 2;
|
||||
n >>= 2;
|
||||
p = a;
|
||||
baddr >>= 2;
|
||||
|
||||
/* first see if write will succeed */
|
||||
for(i = 0; i < n; i++)
|
||||
if((p[i] & flash.p[off+i]) != p[i])
|
||||
error("flash needs erase");
|
||||
|
||||
if(waserror()){
|
||||
ise_reset();
|
||||
flashprogpower(0);
|
||||
nexterror();
|
||||
}
|
||||
flashprogpower(1);
|
||||
|
||||
/*
|
||||
* use the first write to reach
|
||||
* a write buffer boundary. the intel maunal
|
||||
* says writes startng at wb boundaries
|
||||
* maximize speed.
|
||||
*/
|
||||
i = wbsize - (off & (wbsize-1));
|
||||
for(end = p + n; p < end;){
|
||||
if(i > end - p)
|
||||
i = end - p;
|
||||
|
||||
if(ise_wbwrite(p, i, off, baddr, &x) < 0)
|
||||
break;
|
||||
|
||||
off += i;
|
||||
p += i;
|
||||
i = wbsize;
|
||||
}
|
||||
|
||||
ise_clearerror();
|
||||
ise_error(0, x);
|
||||
ise_error(1, x>>16);
|
||||
|
||||
ise_reset();
|
||||
flashprogpower(0);
|
||||
poperror();
|
||||
}
|
||||
|
||||
/* amd/fujitsu standard command set
|
||||
* I don't have an amd chipset to work with
|
||||
* so I'm loathe to write this yet. If someone
|
||||
* else does, please send it to me and I'll
|
||||
* incorporate it -- presotto@bell-labs.com
|
||||
*/
|
||||
static void
|
||||
afs_reset(void)
|
||||
{
|
||||
flash.p[0x55] = mirror(0xf0); /* reset */
|
||||
}
|
||||
static void
|
||||
afs_id(void)
|
||||
{
|
||||
afs_reset();
|
||||
flash.p[0x55] = mirror(0xf0); /* reset */
|
||||
flash.p[0x555] = mirror(0xaa); /* query vendor block */
|
||||
flash.p[0x2aa] = mirror(0x55);
|
||||
flash.p[0x555] = mirror(0x90);
|
||||
flash.manid = flash.p[00];
|
||||
afs_reset();
|
||||
flash.p[0x555] = mirror(0xaa); /* query vendor block */
|
||||
flash.p[0x2aa] = mirror(0x55);
|
||||
flash.p[0x555] = mirror(0x90);
|
||||
flash.devid = flash.p[01];
|
||||
afs_reset();
|
||||
}
|
||||
static void
|
||||
afs_erase(ulong)
|
||||
{
|
||||
error("amd/fujistsu erase not implemented");
|
||||
}
|
||||
static void
|
||||
afs_write(void*, long, ulong)
|
||||
{
|
||||
error("amd/fujistsu write not implemented");
|
||||
}
|
|
@ -1,713 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
#include "io.h"
|
||||
|
||||
/*
|
||||
* BUG: insertion events are detected by polling.
|
||||
* Should look into the compaq docs to see if
|
||||
* there's an interrupt for card insertion
|
||||
* there's probably one.
|
||||
*/
|
||||
|
||||
static PCMslot slot[2];
|
||||
int nslot = 2;
|
||||
|
||||
struct {
|
||||
Ref;
|
||||
Rendez event; // where to wait for card events
|
||||
int evreader; // there's a reader for events
|
||||
} pcmcia;
|
||||
|
||||
enum
|
||||
{
|
||||
Qdir,
|
||||
Qmem,
|
||||
Qattr,
|
||||
Qctl,
|
||||
Qevs,
|
||||
|
||||
Nents = 3,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/*
|
||||
* configuration registers - they start at an offset in attribute
|
||||
* memory found in the CIS.
|
||||
*/
|
||||
Rconfig= 0,
|
||||
Creset= (1<<7), /* reset device */
|
||||
Clevel= (1<<6), /* level sensitive interrupt line */
|
||||
};
|
||||
|
||||
static void increfp(PCMslot*);
|
||||
static void decrefp(PCMslot*);
|
||||
static void slotmap(int, ulong, ulong, ulong);
|
||||
static void slottiming(int, int, int, int, int);
|
||||
static void slotinfo(Ureg*, void*);
|
||||
|
||||
#define TYPE(c) (((ulong)c->qid.path)&0xff)
|
||||
#define PATH(s,t) (((s)<<8)|(t))
|
||||
|
||||
static PCMslot*
|
||||
slotof(Chan *c)
|
||||
{
|
||||
ulong x;
|
||||
|
||||
x = c->qid.path;
|
||||
return slot + ((x>>8)&0xff);
|
||||
}
|
||||
|
||||
static int
|
||||
pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp)
|
||||
{
|
||||
int slotno;
|
||||
Qid qid;
|
||||
long len;
|
||||
PCMslot *sp;
|
||||
|
||||
if(i == DEVDOTDOT){
|
||||
mkqid(&qid, Qdir, 0, QTDIR);
|
||||
devdir(c, qid, "#y", 0, eve, 0555, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(i >= Nents*nslot + 1)
|
||||
return -1;
|
||||
if(i == Nents*nslot){
|
||||
len = 0;
|
||||
qid.path = PATH(0, Qevs);
|
||||
snprint(up->genbuf, sizeof up->genbuf, "pcmevs");
|
||||
goto found;
|
||||
}
|
||||
|
||||
slotno = i/Nents;
|
||||
sp = slot + slotno;
|
||||
len = 0;
|
||||
switch(i%Nents){
|
||||
case 0:
|
||||
qid.path = PATH(slotno, Qmem);
|
||||
snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
|
||||
len = sp->memlen;
|
||||
break;
|
||||
case 1:
|
||||
qid.path = PATH(slotno, Qattr);
|
||||
snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
|
||||
len = sp->memlen;
|
||||
break;
|
||||
case 2:
|
||||
qid.path = PATH(slotno, Qctl);
|
||||
snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
|
||||
break;
|
||||
}
|
||||
found:
|
||||
qid.vers = 0;
|
||||
qid.type = QTFILE;
|
||||
devdir(c, qid, up->genbuf, len, eve, 0660, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
bitno(ulong x)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8*sizeof(x); i++)
|
||||
if((1<<i) & x)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* set up the cards, default timing is 300 ns
|
||||
*/
|
||||
static void
|
||||
pcmciareset(void)
|
||||
{
|
||||
/* staticly map the whole area */
|
||||
slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM);
|
||||
slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM);
|
||||
|
||||
/* set timing to the default, 300 */
|
||||
slottiming(0, 300, 300, 300, 0);
|
||||
slottiming(1, 300, 300, 300, 0);
|
||||
|
||||
/* if there's no pcmcia sleave, no interrupts */
|
||||
if(gpioregs->level & GPIO_OPT_IND_i)
|
||||
return;
|
||||
|
||||
/* sleave there, interrupt on card removal */
|
||||
intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status");
|
||||
intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");
|
||||
}
|
||||
|
||||
static Chan*
|
||||
pcmciaattach(char *spec)
|
||||
{
|
||||
return devattach('y', spec);
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
pcmciawalk(Chan *c, Chan *nc, char **name, int nname)
|
||||
{
|
||||
return devwalk(c, nc, name, nname, 0, 0, pcmgen);
|
||||
}
|
||||
|
||||
static int
|
||||
pcmciastat(Chan *c, uchar *db, int n)
|
||||
{
|
||||
return devstat(c, db, n, 0, 0, pcmgen);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
pcmciaopen(Chan *c, int omode)
|
||||
{
|
||||
PCMslot *slotp;
|
||||
|
||||
if(c->qid.type & QTDIR){
|
||||
if(omode != OREAD)
|
||||
error(Eperm);
|
||||
} else {
|
||||
slotp = slotof(c);
|
||||
increfp(slotp);
|
||||
}
|
||||
c->mode = openmode(omode);
|
||||
c->flag |= COPEN;
|
||||
c->offset = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
pcmciaclose(Chan *c)
|
||||
{
|
||||
if(c->flag & COPEN)
|
||||
if((c->qid.type & QTDIR) == 0)
|
||||
decrefp(slotof(c));
|
||||
}
|
||||
|
||||
/* a memmove using only bytes */
|
||||
static void
|
||||
memmoveb(uchar *to, uchar *from, int n)
|
||||
{
|
||||
while(n-- > 0)
|
||||
*to++ = *from++;
|
||||
}
|
||||
|
||||
/* a memmove using only shorts & bytes */
|
||||
static void
|
||||
memmoves(uchar *to, uchar *from, int n)
|
||||
{
|
||||
ushort *t, *f;
|
||||
|
||||
if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
|
||||
while(n-- > 0)
|
||||
*to++ = *from++;
|
||||
} else {
|
||||
n = n/2;
|
||||
t = (ushort*)to;
|
||||
f = (ushort*)from;
|
||||
while(n-- > 0)
|
||||
*t++ = *f++;
|
||||
}
|
||||
}
|
||||
|
||||
static long
|
||||
pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
|
||||
{
|
||||
rlock(sp);
|
||||
if(waserror()){
|
||||
runlock(sp);
|
||||
nexterror();
|
||||
}
|
||||
if(off > len)
|
||||
return 0;
|
||||
if(off + n > len)
|
||||
n = len - off;
|
||||
memmoveb(a, start+off, n);
|
||||
runlock(sp);
|
||||
poperror();
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
pcmctlread(void *a, long n, ulong off, PCMslot *sp)
|
||||
{
|
||||
char *p, *buf, *e;
|
||||
|
||||
buf = p = malloc(READSTR);
|
||||
if(waserror()){
|
||||
free(buf);
|
||||
nexterror();
|
||||
}
|
||||
e = p + READSTR;
|
||||
|
||||
buf[0] = 0;
|
||||
if(sp->occupied){
|
||||
p = seprint(p, e, "occupied\n");
|
||||
if(sp->verstr[0])
|
||||
p = seprint(p, e, "version %s\n", sp->verstr);
|
||||
}
|
||||
USED(p);
|
||||
|
||||
n = readstr(off, a, n, buf);
|
||||
free(buf);
|
||||
poperror();
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
inserted(void *)
|
||||
{
|
||||
if (slot[0].inserted)
|
||||
return 1;
|
||||
if (slot[1].inserted)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
pcmevsread(void *a, long n, ulong off)
|
||||
{
|
||||
int i;
|
||||
char *buf = nil;
|
||||
char *e;
|
||||
|
||||
if (pcmcia.evreader)
|
||||
error("At most one reader");
|
||||
off = 0;
|
||||
pcmcia.evreader++;
|
||||
if (waserror()){
|
||||
free(buf);
|
||||
pcmcia.evreader--;
|
||||
nexterror();
|
||||
}
|
||||
while((i = inserted(nil)) == 0){
|
||||
slotinfo(nil, nil);
|
||||
tsleep(&pcmcia.event, inserted, nil, 500);
|
||||
}
|
||||
pcmcia.evreader--;
|
||||
slot[i-1].inserted = 0;
|
||||
buf = malloc(READSTR);
|
||||
e = buf + READSTR;
|
||||
buf[0] = 0;
|
||||
seprint(buf, e, "#y/pcm%dctl\n", i-1);
|
||||
n = readstr(off, a, n, buf);
|
||||
free(buf);
|
||||
poperror();
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
pcmciaread(Chan *c, void *a, long n, vlong off)
|
||||
{
|
||||
PCMslot *sp;
|
||||
ulong offset = off;
|
||||
|
||||
sp = slotof(c);
|
||||
|
||||
switch(TYPE(c)){
|
||||
case Qdir:
|
||||
return devdirread(c, a, n, 0, 0, pcmgen);
|
||||
case Qmem:
|
||||
if(!sp->occupied)
|
||||
error(Eio);
|
||||
return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg);
|
||||
case Qattr:
|
||||
if(!sp->occupied)
|
||||
error(Eio);
|
||||
return pcmread(a, n, offset, sp, sp->attr, OneMeg);
|
||||
case Qevs:
|
||||
return pcmevsread(a, n, offset);
|
||||
case Qctl:
|
||||
return pcmctlread(a, n, offset, sp);
|
||||
}
|
||||
error(Ebadarg);
|
||||
return -1; /* not reached */
|
||||
}
|
||||
|
||||
static long
|
||||
pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
|
||||
{
|
||||
rlock(sp);
|
||||
if(waserror()){
|
||||
runlock(sp);
|
||||
nexterror();
|
||||
}
|
||||
if(off > len)
|
||||
error(Eio);
|
||||
if(off + n > len)
|
||||
error(Eio);
|
||||
memmoveb(start+off, a, n);
|
||||
poperror();
|
||||
runlock(sp);
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
pcmctlwrite(char *p, long n, ulong, PCMslot *sp)
|
||||
{
|
||||
Cmdbuf *cmd;
|
||||
uchar *cp;
|
||||
int index, i, dtx;
|
||||
Rune r;
|
||||
DevConf cf;
|
||||
Devport port;
|
||||
|
||||
cmd = parsecmd(p, n);
|
||||
if(strcmp(cmd->f[0], "configure") == 0){
|
||||
wlock(sp);
|
||||
if(waserror()){
|
||||
wunlock(sp);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
/* see if driver exists and is configurable */
|
||||
if(cmd->nf < 3)
|
||||
error(Ebadarg);
|
||||
p = cmd->f[1];
|
||||
if(*p++ != '#')
|
||||
error(Ebadarg);
|
||||
p += chartorune(&r, p);
|
||||
dtx = devno(r, 1);
|
||||
if(dtx < 0)
|
||||
error("no such device type");
|
||||
if(devtab[dtx]->config == nil)
|
||||
error("not a dynamicly configurable device");
|
||||
|
||||
/* set pcmcia card configuration */
|
||||
index = 0;
|
||||
if(sp->def != nil)
|
||||
index = sp->def->index;
|
||||
if(cmd->nf > 3){
|
||||
i = atoi(cmd->f[3]);
|
||||
if(i < 0 || i >= sp->nctab)
|
||||
error("bad configuration index");
|
||||
index = i;
|
||||
}
|
||||
if(sp->cfg[0].cpresent & (1<<Rconfig)){
|
||||
cp = sp->attr;
|
||||
cp += sp->cfg[0].caddr + Rconfig;
|
||||
*cp = index;
|
||||
}
|
||||
|
||||
/* configure device */
|
||||
memset(&cf, 0, sizeof cf);
|
||||
kstrdup(&cf.type, cmd->f[2]);
|
||||
cf.mem = (ulong)sp->mem;
|
||||
cf.ports = &port;
|
||||
cf.ports[0].port = (ulong)sp->regs;
|
||||
cf.ports[0].size = 0;
|
||||
cf.nports = 1;
|
||||
cf.itype = GPIOfalling;
|
||||
cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i);
|
||||
if(devtab[dtx]->config(1, p, &cf) < 0)
|
||||
error("couldn't configure device");
|
||||
sp->dev = devtab[dtx];
|
||||
free(cf.type);
|
||||
wunlock(sp);
|
||||
poperror();
|
||||
|
||||
/* don't let the power turn off */
|
||||
increfp(sp);
|
||||
}else if(strcmp(cmd->f[0], "remove") == 0){
|
||||
/* see if driver exists and is configurable */
|
||||
if(cmd->nf != 2)
|
||||
error(Ebadarg);
|
||||
p = cmd->f[1];
|
||||
if(*p++ != '#')
|
||||
error(Ebadarg);
|
||||
p += chartorune(&r, p);
|
||||
dtx = devno(r, 1);
|
||||
if(dtx < 0)
|
||||
error("no such device type");
|
||||
if(devtab[dtx]->config == nil)
|
||||
error("not a dynamicly configurable device");
|
||||
if(devtab[dtx]->config(0, p, nil) < 0)
|
||||
error("couldn't unconfigure device");
|
||||
|
||||
/* let the power turn off */
|
||||
decrefp(sp);
|
||||
}
|
||||
free(cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
pcmciawrite(Chan *c, void *a, long n, vlong off)
|
||||
{
|
||||
PCMslot *sp;
|
||||
ulong offset = off;
|
||||
|
||||
sp = slotof(c);
|
||||
|
||||
switch(TYPE(c)){
|
||||
case Qmem:
|
||||
if(!sp->occupied)
|
||||
error(Eio);
|
||||
return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);
|
||||
case Qattr:
|
||||
if(!sp->occupied)
|
||||
error(Eio);
|
||||
return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);
|
||||
case Qevs:
|
||||
break;
|
||||
case Qctl:
|
||||
if(!sp->occupied)
|
||||
error(Eio);
|
||||
return pcmctlwrite(a, n, offset, sp);
|
||||
}
|
||||
error(Ebadarg);
|
||||
return -1; /* not reached */
|
||||
}
|
||||
|
||||
/*
|
||||
* power up/down pcmcia
|
||||
*/
|
||||
void
|
||||
pcmciapower(int on)
|
||||
{
|
||||
PCMslot *sp;
|
||||
|
||||
/* if there's no pcmcia sleave, no interrupts */
|
||||
iprint("pcmciapower %d\n", on);
|
||||
|
||||
if (on){
|
||||
/* set timing to the default, 300 */
|
||||
slottiming(0, 300, 300, 300, 0);
|
||||
slottiming(1, 300, 300, 300, 0);
|
||||
|
||||
/* if there's no pcmcia sleave, no interrupts */
|
||||
if(gpioregs->level & GPIO_OPT_IND_i){
|
||||
iprint("pcmciapower: no sleeve\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (sp = slot; sp < slot + nslot; sp++){
|
||||
if (sp->dev){
|
||||
increfp(sp);
|
||||
iprint("pcmciapower: %s\n", sp->verstr);
|
||||
delay(10000);
|
||||
if (sp->dev->power)
|
||||
sp->dev->power(on);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(gpioregs->level & GPIO_OPT_IND_i){
|
||||
iprint("pcmciapower: no sleeve\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (sp = slot; sp < slot + nslot; sp++){
|
||||
if (sp->dev){
|
||||
if (sp->dev->power)
|
||||
sp->dev->power(on);
|
||||
decrefp(sp);
|
||||
}
|
||||
sp->occupied = 0;
|
||||
sp->cisread = 0;
|
||||
}
|
||||
egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Dev pcmciadevtab = {
|
||||
'y',
|
||||
"pcmcia",
|
||||
|
||||
pcmciareset,
|
||||
devinit,
|
||||
devshutdown,
|
||||
pcmciaattach,
|
||||
pcmciawalk,
|
||||
pcmciastat,
|
||||
pcmciaopen,
|
||||
devcreate,
|
||||
pcmciaclose,
|
||||
pcmciaread,
|
||||
devbread,
|
||||
pcmciawrite,
|
||||
devbwrite,
|
||||
devremove,
|
||||
devwstat,
|
||||
pcmciapower,
|
||||
};
|
||||
|
||||
/* see what's there */
|
||||
static void
|
||||
slotinfo(Ureg*, void*)
|
||||
{
|
||||
ulong x = gpioregs->level;
|
||||
|
||||
if(x & GPIO_OPT_IND_i){
|
||||
/* no expansion pack */
|
||||
slot[0].occupied = slot[0].inserted = 0;
|
||||
slot[1].occupied = slot[1].inserted = 0;
|
||||
} else {
|
||||
if(x & GPIO_CARD_IND0_i){
|
||||
slot[0].occupied = slot[0].inserted = 0;
|
||||
slot[0].cisread = 0;
|
||||
} else {
|
||||
if(slot[0].occupied == 0){
|
||||
slot[0].inserted = 1;
|
||||
slot[0].cisread = 0;
|
||||
}
|
||||
slot[0].occupied = 1;
|
||||
}
|
||||
if(x & GPIO_CARD_IND1_i){
|
||||
slot[1].occupied = slot[1].inserted = 0;
|
||||
slot[1].cisread = 0;
|
||||
} else {
|
||||
if(slot[1].occupied == 0){
|
||||
slot[1].inserted = 1;
|
||||
slot[1].cisread = 0;
|
||||
}
|
||||
slot[1].occupied = 1;
|
||||
}
|
||||
if (inserted(nil))
|
||||
wakeup(&pcmcia.event);
|
||||
}
|
||||
}
|
||||
|
||||
/* use reference card to turn cards on and off */
|
||||
static void
|
||||
increfp(PCMslot *sp)
|
||||
{
|
||||
wlock(sp);
|
||||
if(waserror()){
|
||||
wunlock(sp);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
iprint("increfp %ld\n", sp - slot);
|
||||
if(incref(&pcmcia) == 1){
|
||||
iprint("increfp full power\n");
|
||||
egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
|
||||
delay(200);
|
||||
egpiobits(EGPIO_pcmcia_reset, 1);
|
||||
delay(100);
|
||||
egpiobits(EGPIO_pcmcia_reset, 0);
|
||||
delay(500);
|
||||
}
|
||||
incref(&sp->ref);
|
||||
slotinfo(nil, nil);
|
||||
if(sp->occupied && sp->cisread == 0) {
|
||||
pcmcisread(sp);
|
||||
}
|
||||
|
||||
wunlock(sp);
|
||||
poperror();
|
||||
}
|
||||
|
||||
static void
|
||||
decrefp(PCMslot *sp)
|
||||
{
|
||||
iprint("decrefp %ld\n", sp - slot);
|
||||
decref(&sp->ref);
|
||||
if(decref(&pcmcia) == 0){
|
||||
iprint("increfp power down\n");
|
||||
egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the regions are staticly mapped
|
||||
*/
|
||||
static void
|
||||
slotmap(int slotno, ulong regs, ulong attr, ulong mem)
|
||||
{
|
||||
PCMslot *sp;
|
||||
|
||||
sp = &slot[slotno];
|
||||
sp->slotno = slotno;
|
||||
sp->memlen = 64*OneMeg;
|
||||
sp->verstr[0] = 0;
|
||||
|
||||
sp->mem = mapmem(mem, 64*OneMeg, 0);
|
||||
sp->memmap.ca = 0;
|
||||
sp->memmap.cea = 64*MB;
|
||||
sp->memmap.isa = (ulong)mem;
|
||||
sp->memmap.len = 64*OneMeg;
|
||||
sp->memmap.attr = 0;
|
||||
|
||||
sp->attr = mapmem(attr, OneMeg, 0);
|
||||
sp->attrmap.ca = 0;
|
||||
sp->attrmap.cea = MB;
|
||||
sp->attrmap.isa = (ulong)attr;
|
||||
sp->attrmap.len = OneMeg;
|
||||
sp->attrmap.attr = 1;
|
||||
|
||||
sp->regs = mapspecial(regs, 32*1024);
|
||||
}
|
||||
|
||||
PCMmap*
|
||||
pcmmap(int slotno, ulong, int, int attr)
|
||||
{
|
||||
if(slotno > nslot)
|
||||
panic("pcmmap");
|
||||
if(attr)
|
||||
return &slot[slotno].attrmap;
|
||||
else
|
||||
return &slot[slotno].memmap;
|
||||
}
|
||||
|
||||
void
|
||||
pcmunmap(int, PCMmap*)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* setup card timings
|
||||
* times are in ns
|
||||
* count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle
|
||||
*
|
||||
*/
|
||||
static int
|
||||
ns2count(int ns)
|
||||
{
|
||||
ulong y;
|
||||
|
||||
/* get 100 times cycle time */
|
||||
y = 100000000/(conf.hz/1000);
|
||||
|
||||
/* get 10 times ns/(cycle*6) */
|
||||
y = (1000*ns)/(6*y);
|
||||
|
||||
/* round up */
|
||||
y += 9;
|
||||
y /= 10;
|
||||
|
||||
/* subtract 1 */
|
||||
return y-1;
|
||||
}
|
||||
static void
|
||||
slottiming(int slotno, int tio, int tattr, int tmem, int fast)
|
||||
{
|
||||
ulong x;
|
||||
|
||||
x = 0;
|
||||
if(fast)
|
||||
x |= 1<<MECR_fast0;
|
||||
x |= ns2count(tio) << MECR_io0;
|
||||
x |= ns2count(tattr) << MECR_attr0;
|
||||
x |= ns2count(tmem) << MECR_mem0;
|
||||
if(slotno == 0){
|
||||
x |= memconfregs->mecr & 0xffff0000;
|
||||
} else {
|
||||
x <<= 16;
|
||||
x |= memconfregs->mecr & 0xffff;
|
||||
}
|
||||
memconfregs->mecr = x;
|
||||
}
|
||||
|
||||
/* For compat with ../pc devices. Don't use it for the bitsy
|
||||
*/
|
||||
int
|
||||
pcmspecial(char*, ISAConf*)
|
||||
{
|
||||
return -1;
|
||||
}
|
|
@ -1,510 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
#include <ctype.h>
|
||||
|
||||
typedef struct Mouseinfo Mouseinfo;
|
||||
typedef struct Mousestate Mousestate;
|
||||
typedef struct Calibration Calibration;
|
||||
|
||||
struct Calibration
|
||||
{
|
||||
long scalex;
|
||||
long scaley;
|
||||
long transx;
|
||||
long transy;
|
||||
} calibration = {
|
||||
-16435,
|
||||
23275,
|
||||
253,
|
||||
-23
|
||||
};
|
||||
|
||||
/* The pen goes down, tracks some and goes up again. The pen alone can
|
||||
* only simulate a one-button mouse.
|
||||
* To simulate a more-button (five, in this case) mouse, we use the four
|
||||
* keys along the the bottom of the iPaq as modifiers.
|
||||
* When one (or more) of the modifier keys is (are) down, a pen-down event
|
||||
* causes the corresponding bottons to go down. If no modifier key is
|
||||
* depressed, a pen-down event is translated into a button-one down event.
|
||||
* Releasing the modifier keys has no direct effect. The pen-up event is
|
||||
* the one that triggers mouse-up events.
|
||||
*/
|
||||
struct Mousestate
|
||||
{
|
||||
Point xy; /* mouse.xy */
|
||||
int buttons; /* mouse.buttons */
|
||||
int modifiers; /* state of physical buttons 2, 3, 4, 5 */
|
||||
ulong counter; /* increments every update */
|
||||
ulong msec; /* time of last event */
|
||||
};
|
||||
|
||||
struct Mouseinfo
|
||||
{
|
||||
Lock;
|
||||
Mousestate;
|
||||
ulong lastcounter; /* value when /dev/mouse read */
|
||||
ulong resize;
|
||||
ulong lastresize;
|
||||
Rendez r;
|
||||
Ref;
|
||||
QLock;
|
||||
int open;
|
||||
int inopen;
|
||||
Mousestate queue[16]; /* circular buffer of click events */
|
||||
int ri; /* read index into queue */
|
||||
int wi; /* write index into queue */
|
||||
uchar qfull; /* queue is full */
|
||||
};
|
||||
|
||||
Mouseinfo mouse;
|
||||
int mouseshifted;
|
||||
|
||||
int penmousechanged(void*);
|
||||
static void penmousetrack(int b, int x, int y);
|
||||
|
||||
enum{
|
||||
Qdir,
|
||||
Qmouse,
|
||||
Qmousein,
|
||||
Qmousectl,
|
||||
};
|
||||
|
||||
static Dirtab mousedir[]={
|
||||
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
|
||||
"mouse", {Qmouse}, 0, 0666,
|
||||
"mousein", {Qmousein}, 0, 0220,
|
||||
"mousectl", {Qmousectl}, 0, 0660,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CMcalibrate,
|
||||
CMswap,
|
||||
};
|
||||
|
||||
static Cmdtab penmousecmd[] =
|
||||
{
|
||||
CMcalibrate, "calibrate", 0,
|
||||
CMswap, "swap", 1,
|
||||
};
|
||||
|
||||
static uchar buttonmap[8] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
};
|
||||
static int mouseswap;
|
||||
|
||||
extern Memimage* gscreen;
|
||||
|
||||
void
|
||||
penbutton(int up, int b) {
|
||||
// button 5 (side button) immediately causes an event
|
||||
// when the pen is down (button 1), other buttons also
|
||||
// cause events, allowing chording with button 1
|
||||
if ((b & 0x20) || (mouse.buttons & 0x1)) {
|
||||
if (up)
|
||||
mouse.buttons &= ~b;
|
||||
else
|
||||
mouse.buttons |= b;
|
||||
penmousetrack(mouse.buttons, -1, -1);
|
||||
} else {
|
||||
if (up)
|
||||
mouse.modifiers &= ~b;
|
||||
else
|
||||
mouse.modifiers |= b;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pentrackxy(int x, int y) {
|
||||
|
||||
if (x == -1) {
|
||||
/* pen up. associate with button 1 through 5 up */
|
||||
mouse.buttons &= ~0x1f;
|
||||
} else {
|
||||
x = ((x*calibration.scalex)>>16) + calibration.transx;
|
||||
y = ((y*calibration.scaley)>>16) + calibration.transy;
|
||||
if ((mouse.buttons & 0x1f) == 0) {
|
||||
if (mouse.modifiers)
|
||||
mouse.buttons |= mouse.modifiers;
|
||||
else
|
||||
mouse.buttons |= 0x1;
|
||||
}
|
||||
}
|
||||
penmousetrack(mouse.buttons, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
penmousereset(void)
|
||||
{
|
||||
if(!conf.monitor)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
penmouseinit(void)
|
||||
{
|
||||
if(!conf.monitor)
|
||||
return;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
penmouseattach(char *spec)
|
||||
{
|
||||
if(!conf.monitor)
|
||||
error(Egreg);
|
||||
return devattach('m', spec);
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
penmousewalk(Chan *c, Chan *nc, char **name, int nname)
|
||||
{
|
||||
return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
|
||||
}
|
||||
|
||||
static int
|
||||
penmousestat(Chan *c, uchar *db, int n)
|
||||
{
|
||||
return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
penmouseopen(Chan *c, int omode)
|
||||
{
|
||||
switch((ulong)c->qid.path){
|
||||
case Qdir:
|
||||
if(omode != OREAD)
|
||||
error(Eperm);
|
||||
break;
|
||||
case Qmouse:
|
||||
lock(&mouse);
|
||||
if(mouse.open){
|
||||
unlock(&mouse);
|
||||
error(Einuse);
|
||||
}
|
||||
mouse.open = 1;
|
||||
mouse.ref++;
|
||||
unlock(&mouse);
|
||||
break;
|
||||
case Qmousein:
|
||||
/* error("disabled"); */
|
||||
lock(&mouse);
|
||||
if(mouse.inopen){
|
||||
unlock(&mouse);
|
||||
error(Einuse);
|
||||
}
|
||||
mouse.inopen = 1;
|
||||
unlock(&mouse);
|
||||
break;
|
||||
default:
|
||||
incref(&mouse);
|
||||
}
|
||||
c->mode = openmode(omode);
|
||||
c->flag |= COPEN;
|
||||
c->offset = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
penmousecreate(Chan*, char*, int, ulong)
|
||||
{
|
||||
if(!conf.monitor)
|
||||
error(Egreg);
|
||||
error(Eperm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
penmouseclose(Chan *c)
|
||||
{
|
||||
if(c->qid.path != Qdir && (c->flag&COPEN)){
|
||||
lock(&mouse);
|
||||
if(c->qid.path == Qmouse)
|
||||
mouse.open = 0;
|
||||
else if(c->qid.path == Qmousein){
|
||||
mouse.inopen = 0;
|
||||
unlock(&mouse);
|
||||
return;
|
||||
}
|
||||
--mouse.ref;
|
||||
unlock(&mouse);
|
||||
}
|
||||
}
|
||||
|
||||
static long
|
||||
penmouseread(Chan *c, void *va, long n, vlong)
|
||||
{
|
||||
char buf[4*12+1];
|
||||
static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
Mousestate m;
|
||||
|
||||
switch((ulong)c->qid.path){
|
||||
case Qdir:
|
||||
return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
|
||||
|
||||
case Qmousectl:
|
||||
sprint(buf, "c%11ld %11ld %11ld %11ld",
|
||||
calibration.scalex, calibration.scaley,
|
||||
calibration.transx, calibration.transy);
|
||||
if(n > 1+4*12)
|
||||
n = 1+4*12;
|
||||
memmove(va, buf, n);
|
||||
return n;
|
||||
|
||||
case Qmouse:
|
||||
while(penmousechanged(0) == 0)
|
||||
sleep(&mouse.r, penmousechanged, 0);
|
||||
|
||||
mouse.qfull = 0;
|
||||
|
||||
/*
|
||||
* No lock of the indices is necessary here, because ri is only
|
||||
* updated by us, and there is only one mouse reader
|
||||
* at a time. I suppose that more than one process
|
||||
* could try to read the fd at one time, but such behavior
|
||||
* is degenerate and already violates the calling
|
||||
* conventions for sleep above.
|
||||
*/
|
||||
if(mouse.ri != mouse.wi) {
|
||||
m = mouse.queue[mouse.ri];
|
||||
if(++mouse.ri == nelem(mouse.queue))
|
||||
mouse.ri = 0;
|
||||
} else {
|
||||
m = mouse.Mousestate;
|
||||
}
|
||||
sprint(buf, "m%11d %11d %11d %11lud",
|
||||
m.xy.x, m.xy.y,
|
||||
m.buttons,
|
||||
m.msec);
|
||||
mouse.lastcounter = m.counter;
|
||||
if(n > 1+4*12)
|
||||
n = 1+4*12;
|
||||
if(mouse.lastresize != mouse.resize){
|
||||
mouse.lastresize = mouse.resize;
|
||||
buf[0] = 'r';
|
||||
}
|
||||
memmove(va, buf, n);
|
||||
return n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setbuttonmap(char* map)
|
||||
{
|
||||
int i, x, one, two, three;
|
||||
|
||||
one = two = three = 0;
|
||||
for(i = 0; i < 3; i++){
|
||||
if(map[i] == 0)
|
||||
error(Ebadarg);
|
||||
if(map[i] == '1'){
|
||||
if(one)
|
||||
error(Ebadarg);
|
||||
one = 1<<i;
|
||||
}
|
||||
else if(map[i] == '2'){
|
||||
if(two)
|
||||
error(Ebadarg);
|
||||
two = 1<<i;
|
||||
}
|
||||
else if(map[i] == '3'){
|
||||
if(three)
|
||||
error(Ebadarg);
|
||||
three = 1<<i;
|
||||
}
|
||||
else
|
||||
error(Ebadarg);
|
||||
}
|
||||
if(map[i])
|
||||
error(Ebadarg);
|
||||
|
||||
memset(buttonmap, 0, 8);
|
||||
for(i = 0; i < 8; i++){
|
||||
x = 0;
|
||||
if(i & 1)
|
||||
x |= one;
|
||||
if(i & 2)
|
||||
x |= two;
|
||||
if(i & 4)
|
||||
x |= three;
|
||||
buttonmap[x] = i;
|
||||
}
|
||||
}
|
||||
|
||||
static long
|
||||
penmousewrite(Chan *c, void *va, long n, vlong)
|
||||
{
|
||||
char *p;
|
||||
Point pt;
|
||||
Cmdbuf *cb;
|
||||
Cmdtab *ct;
|
||||
char buf[64];
|
||||
int b;
|
||||
|
||||
p = va;
|
||||
switch((ulong)c->qid.path){
|
||||
case Qdir:
|
||||
error(Eisdir);
|
||||
|
||||
case Qmousectl:
|
||||
cb = parsecmd(va, n);
|
||||
if(waserror()){
|
||||
free(cb);
|
||||
nexterror();
|
||||
}
|
||||
ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd));
|
||||
switch(ct->index){
|
||||
case CMswap:
|
||||
if(mouseswap)
|
||||
setbuttonmap("123");
|
||||
else
|
||||
setbuttonmap("321");
|
||||
mouseswap ^= 1;
|
||||
break;
|
||||
case CMcalibrate:
|
||||
if (cb->nf == 1) {
|
||||
calibration.scalex = 1<<16;
|
||||
calibration.scaley = 1<<16;
|
||||
calibration.transx = 0;
|
||||
calibration.transy = 0;
|
||||
} else if (cb->nf == 5) {
|
||||
if ((!isdigit(*cb->f[1]) && *cb->f[1] != '-')
|
||||
|| (!isdigit(*cb->f[2]) && *cb->f[2] != '-')
|
||||
|| (!isdigit(*cb->f[3]) && *cb->f[3] != '-')
|
||||
|| (!isdigit(*cb->f[4]) && *cb->f[4] != '-'))
|
||||
error("bad syntax in control file message");
|
||||
calibration.scalex = strtol(cb->f[1], nil, 0);
|
||||
calibration.scaley = strtol(cb->f[2], nil, 0);
|
||||
calibration.transx = strtol(cb->f[3], nil, 0);
|
||||
calibration.transy = strtol(cb->f[4], nil, 0);
|
||||
} else
|
||||
cmderror(cb, Ecmdargs);
|
||||
break;
|
||||
}
|
||||
free(cb);
|
||||
poperror();
|
||||
return n;
|
||||
|
||||
case Qmousein:
|
||||
if(n > sizeof buf-1)
|
||||
n = sizeof buf -1;
|
||||
memmove(buf, va, n);
|
||||
buf[n] = 0;
|
||||
p = 0;
|
||||
pt.x = strtol(buf+1, &p, 0);
|
||||
if(p == 0)
|
||||
error(Eshort);
|
||||
pt.y = strtol(p, &p, 0);
|
||||
if(p == 0)
|
||||
error(Eshort);
|
||||
b = strtol(p, &p, 0);
|
||||
penmousetrack(b, pt.x, pt.y);
|
||||
return n;
|
||||
|
||||
case Qmouse:
|
||||
if(n > sizeof buf-1)
|
||||
n = sizeof buf -1;
|
||||
memmove(buf, va, n);
|
||||
buf[n] = 0;
|
||||
p = 0;
|
||||
pt.x = strtoul(buf+1, &p, 0);
|
||||
if(p == 0)
|
||||
error(Eshort);
|
||||
pt.y = strtoul(p, 0, 0);
|
||||
qlock(&mouse);
|
||||
if(ptinrect(pt, gscreen->r))
|
||||
penmousetrack(mouse.buttons, pt.x, pt.y);
|
||||
qunlock(&mouse);
|
||||
return n;
|
||||
}
|
||||
|
||||
error(Egreg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Dev penmousedevtab = {
|
||||
'm',
|
||||
"penmouse",
|
||||
|
||||
penmousereset,
|
||||
penmouseinit,
|
||||
devshutdown,
|
||||
penmouseattach,
|
||||
penmousewalk,
|
||||
penmousestat,
|
||||
penmouseopen,
|
||||
penmousecreate,
|
||||
penmouseclose,
|
||||
penmouseread,
|
||||
devbread,
|
||||
penmousewrite,
|
||||
devbwrite,
|
||||
devremove,
|
||||
devwstat,
|
||||
};
|
||||
|
||||
/*
|
||||
* called at interrupt level to update the structure and
|
||||
* awaken any waiting procs.
|
||||
*/
|
||||
static void
|
||||
penmousetrack(int b, int x, int y)
|
||||
{
|
||||
int lastb;
|
||||
|
||||
if (x >= 0)
|
||||
mouse.xy = Pt(x, y);
|
||||
lastb = mouse.buttons;
|
||||
mouse.buttons = b;
|
||||
mouse.counter++;
|
||||
mouse.msec = TK2MS(MACHP(0)->ticks);
|
||||
|
||||
/*
|
||||
* if the queue fills, we discard the entire queue and don't
|
||||
* queue any more events until a reader polls the mouse.
|
||||
*/
|
||||
if(!mouse.qfull && lastb != b) { /* add to ring */
|
||||
mouse.queue[mouse.wi] = mouse.Mousestate;
|
||||
if(++mouse.wi == nelem(mouse.queue))
|
||||
mouse.wi = 0;
|
||||
if(mouse.wi == mouse.ri)
|
||||
mouse.qfull = 1;
|
||||
}
|
||||
wakeup(&mouse.r);
|
||||
drawactive(1);
|
||||
resetsuspendtimer();
|
||||
}
|
||||
|
||||
int
|
||||
penmousechanged(void*)
|
||||
{
|
||||
return mouse.lastcounter != mouse.counter ||
|
||||
mouse.lastresize != mouse.resize;
|
||||
}
|
||||
|
||||
Point
|
||||
penmousexy(void)
|
||||
{
|
||||
return mouse.xy;
|
||||
}
|
||||
|
||||
/*
|
||||
* notify reader that screen has been resized (ha!)
|
||||
*/
|
||||
void
|
||||
mouseresize(void)
|
||||
{
|
||||
mouse.resize++;
|
||||
wakeup(&mouse.r);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,407 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
enum{
|
||||
Qdir,
|
||||
Qbacklight,
|
||||
Qbattery,
|
||||
Qbuttons,
|
||||
Qcruft,
|
||||
Qled,
|
||||
Qversion,
|
||||
Qpower,
|
||||
|
||||
/* command types */
|
||||
BLversion= 0,
|
||||
BLbuttons= 2, /* button events */
|
||||
BLtouch= 3, /* read touch screen events */
|
||||
BLled= 8, /* turn LED on/off */
|
||||
BLbattery= 9, /* read battery status */
|
||||
BLbacklight= 0xd, /* backlight control */
|
||||
|
||||
SOF= 0x2, /* start of frame */
|
||||
};
|
||||
|
||||
Dirtab µcdir[]={
|
||||
".", { Qdir, 0, QTDIR }, 0, DMDIR|0755,
|
||||
"backlight", { Qbacklight, 0 }, 0, 0664,
|
||||
"battery", { Qbattery, 0 }, 0, 0664,
|
||||
"buttons", { Qbuttons, 0 }, 0, 0664,
|
||||
"cruft", { Qcruft, 0 }, 0, 0664,
|
||||
"led", { Qled, 0 }, 0, 0664,
|
||||
"version", { Qversion, 0 }, 0, 0664,
|
||||
"power", { Qpower, 0 }, 0, 0600,
|
||||
};
|
||||
|
||||
static struct µcontroller
|
||||
{
|
||||
/* message being rcvd */
|
||||
int state;
|
||||
uchar buf[16+4];
|
||||
uchar n;
|
||||
|
||||
/* for messages that require acks */
|
||||
QLock;
|
||||
Rendez r;
|
||||
|
||||
/* battery */
|
||||
uchar acstatus;
|
||||
uchar voltage;
|
||||
ushort batstatus;
|
||||
uchar batchem;
|
||||
|
||||
/* version string */
|
||||
char version[16+2];
|
||||
} ctlr;
|
||||
|
||||
extern int landscape;
|
||||
|
||||
int
|
||||
µcputc(Queue*, int ch)
|
||||
{
|
||||
int i, len, b, up;
|
||||
uchar cksum;
|
||||
uchar *p;
|
||||
static int samseq;
|
||||
static int touching; /* guard against something we call going spllo() */
|
||||
static int buttoning; /* guard against something we call going spllo() */
|
||||
|
||||
if(ctlr.n > sizeof(ctlr.buf))
|
||||
panic("µcputc");
|
||||
|
||||
ctlr.buf[ctlr.n++] = (uchar)ch;
|
||||
|
||||
for(;;){
|
||||
/* message hasn't started yet? */
|
||||
if(ctlr.buf[0] != SOF){
|
||||
p = memchr(ctlr.buf, SOF, ctlr.n);
|
||||
if(p == nil){
|
||||
ctlr.n = 0;
|
||||
break;
|
||||
} else {
|
||||
ctlr.n -= p-ctlr.buf;
|
||||
memmove(ctlr.buf, p, ctlr.n);
|
||||
}
|
||||
}
|
||||
|
||||
/* whole msg? */
|
||||
len = ctlr.buf[1] & 0xf;
|
||||
if(ctlr.n < 3 || ctlr.n < len+3)
|
||||
break;
|
||||
|
||||
/* check the sum */
|
||||
ctlr.buf[0] = ~SOF; /* make sure we process this msg exactly once */
|
||||
cksum = 0;
|
||||
for(i = 1; i < len+2; i++)
|
||||
cksum += ctlr.buf[i];
|
||||
if(ctlr.buf[len+2] != cksum)
|
||||
continue;
|
||||
|
||||
/* parse resulting message */
|
||||
p = ctlr.buf+2;
|
||||
switch(ctlr.buf[1] >> 4){
|
||||
case BLversion:
|
||||
strncpy(ctlr.version, (char*)p, len);
|
||||
ctlr.version[len] = '0';
|
||||
strcat(ctlr.version, "\n");
|
||||
wakeup(&ctlr.r);
|
||||
break;
|
||||
case BLbuttons:
|
||||
if(len < 1 || buttoning)
|
||||
break;
|
||||
buttoning = 1;
|
||||
b = p[0] & 0x7f;
|
||||
up = p[0] & 0x80;
|
||||
|
||||
if(b <= 5){
|
||||
/* like mouse buttons */
|
||||
if(--b == 0)
|
||||
b = 5;
|
||||
penbutton(up, 1<<b);
|
||||
}
|
||||
buttoning = 0;
|
||||
break;
|
||||
case BLtouch:
|
||||
if(touching)
|
||||
break;
|
||||
touching = 1;
|
||||
if(len == 4) {
|
||||
if (samseq++ > 10){
|
||||
if (landscape)
|
||||
pentrackxy((p[0]<<8)|p[1], (p[2]<<8)|p[3]);
|
||||
else
|
||||
pentrackxy((p[2]<<8)|p[3], (p[0]<<8)|p[1]);
|
||||
}
|
||||
} else {
|
||||
samseq = 0;
|
||||
pentrackxy(-1, -1);
|
||||
}
|
||||
touching = 0;
|
||||
break;
|
||||
case BLled:
|
||||
wakeup(&ctlr.r);
|
||||
break;
|
||||
case BLbattery:
|
||||
if(len >= 5){
|
||||
ctlr.acstatus = p[0];
|
||||
ctlr.voltage = (p[3]<<8)|p[2];
|
||||
ctlr.batstatus = p[4];
|
||||
ctlr.batchem = p[1];
|
||||
}
|
||||
wakeup(&ctlr.r);
|
||||
break;
|
||||
case BLbacklight:
|
||||
wakeup(&ctlr.r);
|
||||
break;
|
||||
default:
|
||||
print("unknown µc message: %ux", ctlr.buf[1] >> 4);
|
||||
for(i = 0; i < len; i++)
|
||||
print(" %ux", p[i]);
|
||||
print("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* remove the message */
|
||||
ctlr.n -= len+3;
|
||||
memmove(ctlr.buf, &ctlr.buf[len+3], ctlr.n);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_sendmsg(uchar id, uchar *data, int len)
|
||||
{
|
||||
uchar buf[20];
|
||||
uchar cksum;
|
||||
uchar c;
|
||||
uchar *p = buf;
|
||||
int i;
|
||||
|
||||
/* create the message */
|
||||
if(sizeof(buf) < len+4)
|
||||
return;
|
||||
cksum = (id<<4) | len;
|
||||
*p++ = SOF;
|
||||
*p++ = cksum;
|
||||
for(i = 0; i < len; i++){
|
||||
c = data[i];
|
||||
cksum += c;
|
||||
*p++ = c;
|
||||
}
|
||||
*p++ = cksum;
|
||||
|
||||
/* send the message - there should be a more generic way to do this */
|
||||
serialµcputs(buf, p-buf);
|
||||
}
|
||||
|
||||
/* the tsleep takes care of lost acks */
|
||||
static void
|
||||
sendmsgwithack(uchar id, uchar *data, int len)
|
||||
{
|
||||
if(waserror()){
|
||||
qunlock(&ctlr);
|
||||
nexterror();
|
||||
}
|
||||
qlock(&ctlr);
|
||||
_sendmsg(id, data, len);
|
||||
tsleep(&ctlr.r, return0, 0, 100);
|
||||
qunlock(&ctlr);
|
||||
poperror();
|
||||
}
|
||||
|
||||
static void
|
||||
sendmsg(uchar id, uchar *data, int len)
|
||||
{
|
||||
if(waserror()){
|
||||
qunlock(&ctlr);
|
||||
nexterror();
|
||||
}
|
||||
qlock(&ctlr);
|
||||
_sendmsg(id, data, len);
|
||||
qunlock(&ctlr);
|
||||
poperror();
|
||||
}
|
||||
|
||||
void
|
||||
µcinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static Chan*
|
||||
µcattach(char* spec)
|
||||
{
|
||||
return devattach('r', spec);
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
µcwalk(Chan *c, Chan *nc, char **name, int nname)
|
||||
{
|
||||
return devwalk(c, nc, name, nname, µcdir, nelem(µcdir), devgen);
|
||||
}
|
||||
|
||||
static int
|
||||
µcstat(Chan *c, uchar *dp, int n)
|
||||
{
|
||||
return devstat(c, dp, n, µcdir, nelem(µcdir), devgen);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
µcopen(Chan* c, int omode)
|
||||
{
|
||||
omode = openmode(omode);
|
||||
if(!iseve())
|
||||
error(Eperm);
|
||||
return devopen(c, omode, µcdir, nelem(µcdir), devgen);
|
||||
}
|
||||
|
||||
static void
|
||||
µcclose(Chan*)
|
||||
{
|
||||
}
|
||||
|
||||
char*
|
||||
acstatus(int x)
|
||||
{
|
||||
if(x)
|
||||
return "attached";
|
||||
else
|
||||
return "detached";
|
||||
}
|
||||
|
||||
char*
|
||||
batstatus(int x)
|
||||
{
|
||||
switch(x){
|
||||
case 1: return "high";
|
||||
case 2: return "low";
|
||||
case 4: return "critical";
|
||||
case 8: return "charging";
|
||||
case 0x80: return "none";
|
||||
}
|
||||
return "ok";
|
||||
}
|
||||
|
||||
static long
|
||||
µcread(Chan* c, void* a, long n, vlong off)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
if(c->qid.path == Qdir)
|
||||
return devdirread(c, a, n, µcdir, nelem(µcdir), devgen);
|
||||
|
||||
switch((ulong)c->qid.path){
|
||||
case Qbattery:
|
||||
sendmsgwithack(BLbattery, nil, 0); /* send a battery request */
|
||||
sprint(buf, "voltage: %d\nac: %s\nstatus: %s\n", ctlr.voltage,
|
||||
acstatus(ctlr.acstatus),
|
||||
batstatus(ctlr.batstatus));
|
||||
return readstr(off, a, n, buf);
|
||||
case Qversion:
|
||||
sendmsgwithack(BLversion, nil, 0); /* send a battery request */
|
||||
return readstr(off, a, n, ctlr.version);
|
||||
}
|
||||
error(Ebadarg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
|
||||
|
||||
static uchar lightdata[16];
|
||||
|
||||
static long
|
||||
µcwrite(Chan* c, void* a, long n, vlong)
|
||||
{
|
||||
Cmdbuf *cmd;
|
||||
uchar data[16];
|
||||
char str[64];
|
||||
int i, j;
|
||||
ulong l;
|
||||
Rune r;
|
||||
extern ulong resumeaddr[];
|
||||
extern void power_resume(void);
|
||||
|
||||
if(c->qid.path == Qpower){
|
||||
if(!iseve())
|
||||
error(Eperm);
|
||||
if(strncmp(a, "suspend", 7) == 0)
|
||||
*resumeaddr = (ulong)power_resume;
|
||||
else if(strncmp(a, "halt", 4) == 0)
|
||||
*resumeaddr = 0;
|
||||
else if(strncmp(a, "wakeup", 6) == 0){
|
||||
cmd = parsecmd(a, n);
|
||||
if (cmd->nf != 2)
|
||||
error(Ebadarg);
|
||||
l = strtoul(cmd->f[1], 0, 0);
|
||||
rtcalarm(l);
|
||||
return n;
|
||||
} else
|
||||
error(Ebadarg);
|
||||
deepsleep();
|
||||
return n;
|
||||
}
|
||||
|
||||
cmd = parsecmd(a, n);
|
||||
if(cmd->nf > 15)
|
||||
error(Ebadarg);
|
||||
for(i = 0; i < cmd->nf; i++)
|
||||
data[i] = strtol(cmd->f[i], 0, 0);
|
||||
|
||||
switch((ulong)c->qid.path){
|
||||
case Qled:
|
||||
sendmsgwithack(BLled, data, cmd->nf);
|
||||
break;
|
||||
case Qbacklight:
|
||||
memmove(lightdata, data, 16);
|
||||
sendmsgwithack(BLbacklight, data, cmd->nf);
|
||||
break;
|
||||
case Qcruft:
|
||||
// lcdtweak(cmd);
|
||||
break;
|
||||
default:
|
||||
error(Ebadarg);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
µcpower(int on)
|
||||
{
|
||||
uchar data[16];
|
||||
if (on == 0)
|
||||
return;
|
||||
/* maybe dangerous, not holding the lock */
|
||||
if (lightdata[0] == 0){
|
||||
data[0]= 2;
|
||||
data[1]= 1;
|
||||
data[2]= 0;
|
||||
} else
|
||||
memmove(data, lightdata, 16);
|
||||
_sendmsg(0xd, data, 3);
|
||||
wakeup(&ctlr.r);
|
||||
}
|
||||
|
||||
Dev µcdevtab = {
|
||||
'r',
|
||||
"µc",
|
||||
|
||||
devreset,
|
||||
µcinit,
|
||||
devshutdown,
|
||||
µcattach,
|
||||
µcwalk,
|
||||
µcstat,
|
||||
µcopen,
|
||||
devcreate,
|
||||
µcclose,
|
||||
µcread,
|
||||
devbread,
|
||||
µcwrite,
|
||||
devbwrite,
|
||||
devremove,
|
||||
devwstat,
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
enum {
|
||||
MaxEther = 24,
|
||||
Ntypes = 8,
|
||||
};
|
||||
|
||||
typedef struct Ether Ether;
|
||||
struct Ether {
|
||||
DevConf;
|
||||
|
||||
int ctlrno;
|
||||
int tbdf; /* type+busno+devno+funcno */
|
||||
int minmtu;
|
||||
int maxmtu;
|
||||
uchar ea[Eaddrlen];
|
||||
int encry;
|
||||
|
||||
void (*attach)(Ether*); /* filled in by reset routine */
|
||||
void (*detach)(Ether*);
|
||||
void (*transmit)(Ether*);
|
||||
void (*interrupt)(Ureg*, void*);
|
||||
long (*ifstat)(Ether*, void*, long, ulong);
|
||||
long (*ctl)(Ether*, void*, long); /* custom ctl messages */
|
||||
void (*power)(Ether*, int); /* power on/off */
|
||||
void (*shutdown)(Ether*); /* shutdown hardware before reboot */
|
||||
void *ctlr;
|
||||
|
||||
Queue* oq;
|
||||
|
||||
Netif;
|
||||
};
|
||||
|
||||
extern Block* etheriq(Ether*, Block*, int);
|
||||
extern void addethercard(char*, int(*)(Ether*));
|
||||
extern ulong ethercrc(uchar*, int);
|
||||
|
||||
#define NEXT(x, l) (((x)+1)%(l))
|
||||
#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
|
||||
#define HOWMANY(x, y) (((x)+((y)-1))/(y))
|
||||
#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
|
|
@ -1,49 +0,0 @@
|
|||
/* Bitsy pcmcia code for wavelan.c */
|
||||
|
||||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/error.h"
|
||||
#include "../port/netif.h"
|
||||
#include "etherif.h"
|
||||
#include "../pc/wavelan.h"
|
||||
|
||||
static int
|
||||
wavelanpcmciareset(Ether *ether)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
|
||||
if((ctlr = malloc(sizeof(Ctlr))) == nil)
|
||||
return -1;
|
||||
|
||||
ilock(ctlr);
|
||||
ctlr->ctlrno = ether->ctlrno;
|
||||
|
||||
if (ether->ports == nil){
|
||||
ether->ports = malloc(sizeof(Devport));
|
||||
ether->ports[0].port = 0;
|
||||
ether->ports[0].size = 0;
|
||||
ether->nports= 1;
|
||||
}
|
||||
if (ether->ports[0].port==0)
|
||||
ether->ports[0].port=WDfltIOB;
|
||||
ctlr->iob = ether->ports[0].port;
|
||||
|
||||
if(wavelanreset(ether, ctlr) < 0){
|
||||
iunlock(ctlr);
|
||||
free(ctlr);
|
||||
ether->ctlr = nil;
|
||||
return -1;
|
||||
}
|
||||
iunlock(ctlr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
etherwavelanlink(void)
|
||||
{
|
||||
addethercard("wavelan", wavelanpcmciareset);
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
#include "../port/portfns.h"
|
||||
|
||||
void audiopower(int);
|
||||
void audioamppower(int);
|
||||
void audioicpower(int);
|
||||
void cacheflush(void);
|
||||
void cachewb(void);
|
||||
void cachewbaddr(void*);
|
||||
void cachewbregion(ulong, int);
|
||||
ulong cankaddr(ulong);
|
||||
void dcacheinvalidate(void);
|
||||
int cistrcmp(char*, char*);
|
||||
int cistrncmp(char*, char*, int);
|
||||
void clockinit(void);
|
||||
ulong clockpower(int);
|
||||
int cmpswap(long*, long, long);
|
||||
#define coherence()
|
||||
#define cycles(x) do{}while(0)
|
||||
#define dcflush(a, b)
|
||||
void delay(int);
|
||||
void µcpower(int);
|
||||
void deepsleep(void);
|
||||
void dmainit(void);
|
||||
void doze(void);
|
||||
void egpiobits(ulong, int);
|
||||
void evenaddr(ulong);
|
||||
ulong findva(ulong, ulong, ulong);
|
||||
void flashprogpower(int);
|
||||
void flushmmu(void);
|
||||
int fpiarm(Ureg *ur);
|
||||
char* getconf(char*);
|
||||
ulong getcpuid(void);
|
||||
ulong getfar(void);
|
||||
ulong getfsr(void);
|
||||
ulong getcontrol(void);
|
||||
ulong getdac(void);
|
||||
ulong getttb(void);
|
||||
void* getlink(void);
|
||||
#define getpgcolor(a) 0
|
||||
ulong getsp(void);
|
||||
void icacheinvalidate(void);
|
||||
void idle(void);
|
||||
void idlehands(void);
|
||||
uchar inb(ulong);
|
||||
ushort ins(ulong);
|
||||
void inss(ulong, void*, int);
|
||||
ulong inl(ulong);
|
||||
void intrdisable(int, int, void (*)(Ureg*, void*), void*, char*);
|
||||
void intrenable(int, int, void (*)(Ureg*, void*), void*, char*);
|
||||
void irpower(int);
|
||||
#define kexit(a)
|
||||
#define kmapinval()
|
||||
void lcdpower(int);
|
||||
void links(void);
|
||||
void* mapmem(ulong, int, int);
|
||||
void mappedIvecEnable(void);
|
||||
void mappedIvecDisable(void);
|
||||
void* mapspecial(ulong, int);
|
||||
void meminit(void);
|
||||
void mmuinit(void);
|
||||
void mmuenable(void);
|
||||
void mmudisable(void);
|
||||
void mmuinvalidate(void);
|
||||
void mmuinvalidateaddr(ulong);
|
||||
void mmurestart(void);
|
||||
ulong mmu_kaddr(ulong);
|
||||
ulong mmu_paddr(ulong);
|
||||
int µcputc(Queue*, int);
|
||||
void noted(Ureg*, ulong);
|
||||
int notify(Ureg*);
|
||||
void outb(ulong, uchar);
|
||||
void outs(ulong, ushort);
|
||||
void outss(ulong, void*, int);
|
||||
void outl(ulong, ulong);
|
||||
void pcmciapower(int);
|
||||
void pcmcisread(PCMslot*);
|
||||
int pcmcistuple(int, int, int, void*, int);
|
||||
PCMmap* pcmmap(int, ulong, int, int);
|
||||
void pcmunmap(int, PCMmap*);
|
||||
void penbutton(int, int);
|
||||
void pentrackxy(int x, int y);
|
||||
void power_down(void);
|
||||
void powerinit(void);
|
||||
void powerkproc(void*);
|
||||
#define procrestore(p)
|
||||
void procsave(Proc*);
|
||||
void procsetup(Proc*);
|
||||
void procfork(Proc*);
|
||||
void putdac(ulong);
|
||||
void putttb(ulong);
|
||||
void putpid(ulong);
|
||||
void resetsuspendtimer(void);
|
||||
void rs232power(int);
|
||||
void rtcalarm(ulong);
|
||||
void sa1110_uartsetup(int);
|
||||
void screeninit(void);
|
||||
void screenpower(int);
|
||||
void serialµcputs(uchar *str, int n);
|
||||
void setr13(int, ulong*);
|
||||
uchar* tarlookup(uchar*, char*, int*);
|
||||
void timersinit(void);
|
||||
void timeradd(Timer*);
|
||||
void timerdel(Timer*);
|
||||
void timerset(Tval);
|
||||
void touser(void*);
|
||||
void trapdump(char *tag);
|
||||
void trapinit(void);
|
||||
void trapresume(void);
|
||||
int tas(void*);
|
||||
void uartpower(int);
|
||||
int uartstageoutput(Uart*);
|
||||
void uartkick(void*);
|
||||
void uartrecv(Uart*, char);
|
||||
#define userureg(ur) (((ur)->psr & PsrMask) == PsrMusr)
|
||||
void vectors(void);
|
||||
void vtable(void);
|
||||
void wbflush(void);
|
||||
#define KADDR(a) (void*)mmu_kaddr((ulong)(a))
|
||||
#define PADDR(a) mmu_paddr((ulong)(a))
|
||||
|
||||
#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* Floating Point Interpreter.
|
||||
* shamelessly stolen from an original by ark.
|
||||
*/
|
||||
#include "fpi.h"
|
||||
|
||||
void
|
||||
fpiround(Internal *i)
|
||||
{
|
||||
unsigned long guard;
|
||||
|
||||
guard = i->l & GuardMask;
|
||||
i->l &= ~GuardMask;
|
||||
if(guard > (LsBit>>1) || (guard == (LsBit>>1) && (i->l & LsBit))){
|
||||
i->l += LsBit;
|
||||
if(i->l & CarryBit){
|
||||
i->l &= ~CarryBit;
|
||||
i->h++;
|
||||
if(i->h & CarryBit){
|
||||
if (i->h & 0x01)
|
||||
i->l |= CarryBit;
|
||||
i->l >>= 1;
|
||||
i->h >>= 1;
|
||||
i->e++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
matchexponents(Internal *x, Internal *y)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = y->e - x->e;
|
||||
x->e = y->e;
|
||||
if(count >= 2*FractBits){
|
||||
x->l = x->l || x->h;
|
||||
x->h = 0;
|
||||
return;
|
||||
}
|
||||
if(count >= FractBits){
|
||||
count -= FractBits;
|
||||
x->l = x->h|(x->l != 0);
|
||||
x->h = 0;
|
||||
}
|
||||
while(count > 0){
|
||||
count--;
|
||||
if(x->h & 0x01)
|
||||
x->l |= CarryBit;
|
||||
if(x->l & 0x01)
|
||||
x->l |= 2;
|
||||
x->l >>= 1;
|
||||
x->h >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shift(Internal *i)
|
||||
{
|
||||
i->e--;
|
||||
i->h <<= 1;
|
||||
i->l <<= 1;
|
||||
if(i->l & CarryBit){
|
||||
i->l &= ~CarryBit;
|
||||
i->h |= 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
normalise(Internal *i)
|
||||
{
|
||||
while((i->h & HiddenBit) == 0)
|
||||
shift(i);
|
||||
}
|
||||
|
||||
static void
|
||||
renormalise(Internal *i)
|
||||
{
|
||||
if(i->e < -2 * FractBits)
|
||||
i->e = -2 * FractBits;
|
||||
while(i->e < 1){
|
||||
i->e++;
|
||||
if(i->h & 0x01)
|
||||
i->l |= CarryBit;
|
||||
i->h >>= 1;
|
||||
i->l = (i->l>>1)|(i->l & 0x01);
|
||||
}
|
||||
if(i->e >= ExpInfinity)
|
||||
SetInfinity(i);
|
||||
}
|
||||
|
||||
void
|
||||
fpinormalise(Internal *x)
|
||||
{
|
||||
if(!IsWeird(x) && !IsZero(x))
|
||||
normalise(x);
|
||||
}
|
||||
|
||||
void
|
||||
fpiadd(Internal *x, Internal *y, Internal *i)
|
||||
{
|
||||
Internal *t;
|
||||
|
||||
i->s = x->s;
|
||||
if(IsWeird(x) || IsWeird(y)){
|
||||
if(IsNaN(x) || IsNaN(y))
|
||||
SetQNaN(i);
|
||||
else
|
||||
SetInfinity(i);
|
||||
return;
|
||||
}
|
||||
if(x->e > y->e){
|
||||
t = x;
|
||||
x = y;
|
||||
y = t;
|
||||
}
|
||||
matchexponents(x, y);
|
||||
i->e = x->e;
|
||||
i->h = x->h + y->h;
|
||||
i->l = x->l + y->l;
|
||||
if(i->l & CarryBit){
|
||||
i->h++;
|
||||
i->l &= ~CarryBit;
|
||||
}
|
||||
if(i->h & (HiddenBit<<1)){
|
||||
if(i->h & 0x01)
|
||||
i->l |= CarryBit;
|
||||
i->l = (i->l>>1)|(i->l & 0x01);
|
||||
i->h >>= 1;
|
||||
i->e++;
|
||||
}
|
||||
if(IsWeird(i))
|
||||
SetInfinity(i);
|
||||
}
|
||||
|
||||
void
|
||||
fpisub(Internal *x, Internal *y, Internal *i)
|
||||
{
|
||||
Internal *t;
|
||||
|
||||
if(y->e < x->e
|
||||
|| (y->e == x->e && (y->h < x->h || (y->h == x->h && y->l < x->l)))){
|
||||
t = x;
|
||||
x = y;
|
||||
y = t;
|
||||
}
|
||||
i->s = y->s;
|
||||
if(IsNaN(y)){
|
||||
SetQNaN(i);
|
||||
return;
|
||||
}
|
||||
if(IsInfinity(y)){
|
||||
if(IsInfinity(x))
|
||||
SetQNaN(i);
|
||||
else
|
||||
SetInfinity(i);
|
||||
return;
|
||||
}
|
||||
matchexponents(x, y);
|
||||
i->e = y->e;
|
||||
i->h = y->h - x->h;
|
||||
i->l = y->l - x->l;
|
||||
if(i->l < 0){
|
||||
i->l += CarryBit;
|
||||
i->h--;
|
||||
}
|
||||
if(i->h == 0 && i->l == 0)
|
||||
SetZero(i);
|
||||
else while(i->e > 1 && (i->h & HiddenBit) == 0)
|
||||
shift(i);
|
||||
}
|
||||
|
||||
#define CHUNK (FractBits/2)
|
||||
#define CMASK ((1<<CHUNK)-1)
|
||||
#define HI(x) ((short)((x)>>CHUNK) & CMASK)
|
||||
#define LO(x) ((short)(x) & CMASK)
|
||||
#define SPILL(x) ((x)>>CHUNK)
|
||||
#define M(x, y) ((long)a[x]*(long)b[y])
|
||||
#define C(h, l) (((long)((h) & CMASK)<<CHUNK)|((l) & CMASK))
|
||||
|
||||
void
|
||||
fpimul(Internal *x, Internal *y, Internal *i)
|
||||
{
|
||||
long a[4], b[4], c[7], f[4];
|
||||
|
||||
i->s = x->s^y->s;
|
||||
if(IsWeird(x) || IsWeird(y)){
|
||||
if(IsNaN(x) || IsNaN(y) || IsZero(x) || IsZero(y))
|
||||
SetQNaN(i);
|
||||
else
|
||||
SetInfinity(i);
|
||||
return;
|
||||
}
|
||||
else if(IsZero(x) || IsZero(y)){
|
||||
SetZero(i);
|
||||
return;
|
||||
}
|
||||
normalise(x);
|
||||
normalise(y);
|
||||
i->e = x->e + y->e - (ExpBias - 1);
|
||||
|
||||
a[0] = HI(x->h); b[0] = HI(y->h);
|
||||
a[1] = LO(x->h); b[1] = LO(y->h);
|
||||
a[2] = HI(x->l); b[2] = HI(y->l);
|
||||
a[3] = LO(x->l); b[3] = LO(y->l);
|
||||
|
||||
c[6] = M(3, 3);
|
||||
c[5] = M(2, 3) + M(3, 2) + SPILL(c[6]);
|
||||
c[4] = M(1, 3) + M(2, 2) + M(3, 1) + SPILL(c[5]);
|
||||
c[3] = M(0, 3) + M(1, 2) + M(2, 1) + M(3, 0) + SPILL(c[4]);
|
||||
c[2] = M(0, 2) + M(1, 1) + M(2, 0) + SPILL(c[3]);
|
||||
c[1] = M(0, 1) + M(1, 0) + SPILL(c[2]);
|
||||
c[0] = M(0, 0) + SPILL(c[1]);
|
||||
|
||||
f[0] = c[0];
|
||||
f[1] = C(c[1], c[2]);
|
||||
f[2] = C(c[3], c[4]);
|
||||
f[3] = C(c[5], c[6]);
|
||||
|
||||
if((f[0] & HiddenBit) == 0){
|
||||
f[0] <<= 1;
|
||||
f[1] <<= 1;
|
||||
f[2] <<= 1;
|
||||
f[3] <<= 1;
|
||||
if(f[1] & CarryBit){
|
||||
f[0] |= 1;
|
||||
f[1] &= ~CarryBit;
|
||||
}
|
||||
if(f[2] & CarryBit){
|
||||
f[1] |= 1;
|
||||
f[2] &= ~CarryBit;
|
||||
}
|
||||
if(f[3] & CarryBit){
|
||||
f[2] |= 1;
|
||||
f[3] &= ~CarryBit;
|
||||
}
|
||||
i->e--;
|
||||
}
|
||||
i->h = f[0];
|
||||
i->l = f[1];
|
||||
if(f[2] || f[3])
|
||||
i->l |= 1;
|
||||
renormalise(i);
|
||||
}
|
||||
|
||||
void
|
||||
fpidiv(Internal *x, Internal *y, Internal *i)
|
||||
{
|
||||
i->s = x->s^y->s;
|
||||
if(IsNaN(x) || IsNaN(y)
|
||||
|| (IsInfinity(x) && IsInfinity(y)) || (IsZero(x) && IsZero(y))){
|
||||
SetQNaN(i);
|
||||
return;
|
||||
}
|
||||
else if(IsZero(x) || IsInfinity(y)){
|
||||
SetInfinity(i);
|
||||
return;
|
||||
}
|
||||
else if(IsInfinity(x) || IsZero(y)){
|
||||
SetZero(i);
|
||||
return;
|
||||
}
|
||||
normalise(x);
|
||||
normalise(y);
|
||||
i->h = 0;
|
||||
i->l = 0;
|
||||
i->e = y->e - x->e + (ExpBias + 2*FractBits - 1);
|
||||
do{
|
||||
if(y->h > x->h || (y->h == x->h && y->l >= x->l)){
|
||||
i->l |= 0x01;
|
||||
y->h -= x->h;
|
||||
y->l -= x->l;
|
||||
if(y->l < 0){
|
||||
y->l += CarryBit;
|
||||
y->h--;
|
||||
}
|
||||
}
|
||||
shift(y);
|
||||
shift(i);
|
||||
}while ((i->h & HiddenBit) == 0);
|
||||
if(y->h || y->l)
|
||||
i->l |= 0x01;
|
||||
renormalise(i);
|
||||
}
|
||||
|
||||
int
|
||||
fpicmp(Internal *x, Internal *y)
|
||||
{
|
||||
if(IsNaN(x) && IsNaN(y))
|
||||
return 0;
|
||||
if(IsInfinity(x) && IsInfinity(y))
|
||||
return y->s - x->s;
|
||||
if(x->e == y->e && x->h == y->h && x->l == y->l)
|
||||
return y->s - x->s;
|
||||
if(x->e < y->e
|
||||
|| (x->e == y->e && (x->h < y->h || (x->h == y->h && x->l < y->l))))
|
||||
return y->s ? 1: -1;
|
||||
return x->s ? -1: 1;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
typedef long Word;
|
||||
typedef unsigned long Single;
|
||||
typedef struct {
|
||||
unsigned long l;
|
||||
unsigned long h;
|
||||
} Double;
|
||||
|
||||
enum {
|
||||
FractBits = 28,
|
||||
CarryBit = 0x10000000,
|
||||
HiddenBit = 0x08000000,
|
||||
MsBit = HiddenBit,
|
||||
NGuardBits = 3,
|
||||
GuardMask = 0x07,
|
||||
LsBit = (1<<NGuardBits),
|
||||
|
||||
SingleExpBias = 127,
|
||||
SingleExpMax = 255,
|
||||
DoubleExpBias = 1023,
|
||||
DoubleExpMax = 2047,
|
||||
|
||||
ExpBias = DoubleExpBias,
|
||||
ExpInfinity = DoubleExpMax,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned char s;
|
||||
short e;
|
||||
long l; /* 0000FFFFFFFFFFFFFFFFFFFFFFFFFGGG */
|
||||
long h; /* 0000HFFFFFFFFFFFFFFFFFFFFFFFFFFF */
|
||||
} Internal;
|
||||
|
||||
#define IsWeird(n) ((n)->e >= ExpInfinity)
|
||||
#define IsInfinity(n) (IsWeird(n) && (n)->h == HiddenBit && (n)->l == 0)
|
||||
#define SetInfinity(n) ((n)->e = ExpInfinity, (n)->h = HiddenBit, (n)->l = 0)
|
||||
#define IsNaN(n) (IsWeird(n) && (((n)->h & ~HiddenBit) || (n)->l))
|
||||
#define SetQNaN(n) ((n)->s = 0, (n)->e = ExpInfinity, \
|
||||
(n)->h = HiddenBit|(LsBit<<1), (n)->l = 0)
|
||||
#define IsZero(n) ((n)->e == 1 && (n)->h == 0 && (n)->l == 0)
|
||||
#define SetZero(n) ((n)->e = 1, (n)->h = 0, (n)->l = 0)
|
||||
|
||||
/*
|
||||
* fpi.c
|
||||
*/
|
||||
extern void fpiround(Internal *);
|
||||
extern void fpiadd(Internal *, Internal *, Internal *);
|
||||
extern void fpisub(Internal *, Internal *, Internal *);
|
||||
extern void fpimul(Internal *, Internal *, Internal *);
|
||||
extern void fpidiv(Internal *, Internal *, Internal *);
|
||||
extern int fpicmp(Internal *, Internal *);
|
||||
extern void fpinormalise(Internal*);
|
||||
|
||||
/*
|
||||
* fpimem.c
|
||||
*/
|
||||
extern void fpis2i(Internal *, void *);
|
||||
extern void fpid2i(Internal *, void *);
|
||||
extern void fpiw2i(Internal *, void *);
|
||||
extern void fpii2s(void *, Internal *);
|
||||
extern void fpii2d(void *, Internal *);
|
||||
extern void fpii2w(Word *, Internal *);
|
|
@ -1,570 +0,0 @@
|
|||
/*
|
||||
* this doesn't attempt to implement ARM floating-point properties
|
||||
* that aren't visible in the Inferno environment.
|
||||
* all arithmetic is done in double precision.
|
||||
* the FP trap status isn't updated.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
|
||||
#include <ureg.h>
|
||||
|
||||
#include "fpi.h"
|
||||
|
||||
/* undef this if correct kernel r13 isn't in Ureg;
|
||||
* check calculation in fpiarm below
|
||||
*/
|
||||
|
||||
|
||||
#define REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
|
||||
#define FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
|
||||
|
||||
typedef struct FP2 FP2;
|
||||
typedef struct FP1 FP1;
|
||||
|
||||
struct FP2 {
|
||||
char* name;
|
||||
void (*f)(Internal, Internal, Internal*);
|
||||
};
|
||||
|
||||
struct FP1 {
|
||||
char* name;
|
||||
void (*f)(Internal*, Internal*);
|
||||
};
|
||||
|
||||
enum {
|
||||
N = 1<<31,
|
||||
Z = 1<<30,
|
||||
C = 1<<29,
|
||||
V = 1<<28,
|
||||
REGPC = 15,
|
||||
};
|
||||
|
||||
int fpemudebug = 0;
|
||||
|
||||
#undef OFR
|
||||
#define OFR(X) ((ulong)&((Ureg*)0)->X)
|
||||
|
||||
static int roff[] = {
|
||||
OFR(r0), OFR(r1), OFR(r2), OFR(r3),
|
||||
OFR(r4), OFR(r5), OFR(r6), OFR(r7),
|
||||
OFR(r8), OFR(r9), OFR(r10), OFR(r11),
|
||||
OFR(r12), OFR(r13), OFR(r14), OFR(pc),
|
||||
};
|
||||
|
||||
static Internal fpconst[8] = { /* indexed by op&7 */
|
||||
/* s, e, l, h */
|
||||
{0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
|
||||
{0, 0x3FF, 0x00000000, 0x08000000}, /* 1.0 */
|
||||
{0, 0x400, 0x00000000, 0x08000000}, /* 2.0 */
|
||||
{0, 0x400, 0x00000000, 0x0C000000}, /* 3.0 */
|
||||
{0, 0x401, 0x00000000, 0x08000000}, /* 4.0 */
|
||||
{0, 0x401, 0x00000000, 0x0A000000}, /* 5.0 */
|
||||
{0, 0x3FE, 0x00000000, 0x08000000}, /* 0.5 */
|
||||
{0, 0x402, 0x00000000, 0x0A000000}, /* 10.0 */
|
||||
};
|
||||
|
||||
/*
|
||||
* arm binary operations
|
||||
*/
|
||||
|
||||
static void
|
||||
fadd(Internal m, Internal n, Internal *d)
|
||||
{
|
||||
(m.s == n.s? fpiadd: fpisub)(&m, &n, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fsub(Internal m, Internal n, Internal *d)
|
||||
{
|
||||
m.s ^= 1;
|
||||
(m.s == n.s? fpiadd: fpisub)(&m, &n, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fsubr(Internal m, Internal n, Internal *d)
|
||||
{
|
||||
n.s ^= 1;
|
||||
(n.s == m.s? fpiadd: fpisub)(&n, &m, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fmul(Internal m, Internal n, Internal *d)
|
||||
{
|
||||
fpimul(&m, &n, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fdiv(Internal m, Internal n, Internal *d)
|
||||
{
|
||||
fpidiv(&m, &n, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fdivr(Internal m, Internal n, Internal *d)
|
||||
{
|
||||
fpidiv(&n, &m, d);
|
||||
}
|
||||
|
||||
/*
|
||||
* arm unary operations
|
||||
*/
|
||||
|
||||
static void
|
||||
fmov(Internal *m, Internal *d)
|
||||
{
|
||||
*d = *m;
|
||||
}
|
||||
|
||||
static void
|
||||
fmovn(Internal *m, Internal *d)
|
||||
{
|
||||
*d = *m;
|
||||
d->s ^= 1;
|
||||
}
|
||||
|
||||
static void
|
||||
fabsf(Internal *m, Internal *d)
|
||||
{
|
||||
*d = *m;
|
||||
d->s = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
frnd(Internal *m, Internal *d)
|
||||
{
|
||||
short e;
|
||||
|
||||
(m->s? fsub: fadd)(fpconst[6], *m, d);
|
||||
if(IsWeird(d))
|
||||
return;
|
||||
fpiround(d);
|
||||
e = (d->e - ExpBias) + 1;
|
||||
if(e <= 0)
|
||||
SetZero(d);
|
||||
else if(e > FractBits){
|
||||
if(e < 2*FractBits)
|
||||
d->l &= ~((1<<(2*FractBits - e))-1);
|
||||
}else{
|
||||
d->l = 0;
|
||||
if(e < FractBits)
|
||||
d->h &= ~((1<<(FractBits-e))-1);
|
||||
}
|
||||
}
|
||||
|
||||
static FP1 optab1[16] = { /* Fd := OP Fm */
|
||||
[0] {"MOVF", fmov},
|
||||
[1] {"NEGF", fmovn},
|
||||
[2] {"ABSF", fabsf},
|
||||
[3] {"RNDF", frnd},
|
||||
[4] {"SQTF", /*fsqt*/0},
|
||||
/* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */
|
||||
/* URD and NRM aren't implemented */
|
||||
};
|
||||
|
||||
static FP2 optab2[16] = { /* Fd := Fn OP Fm */
|
||||
[0] {"ADDF", fadd},
|
||||
[1] {"MULF", fmul},
|
||||
[2] {"SUBF", fsub},
|
||||
[3] {"RSUBF", fsubr},
|
||||
[4] {"DIVF", fdiv},
|
||||
[5] {"RDIVF", fdivr},
|
||||
/* POW, RPW deprecated */
|
||||
[8] {"REMF", /*frem*/0},
|
||||
[9] {"FMF", fmul}, /* fast multiply */
|
||||
[10] {"FDV", fdiv}, /* fast divide */
|
||||
[11] {"FRD", fdivr}, /* fast reverse divide */
|
||||
/* POL deprecated */
|
||||
};
|
||||
|
||||
static ulong
|
||||
fcmp(Internal *n, Internal *m)
|
||||
{
|
||||
int i;
|
||||
Internal rm, rn;
|
||||
|
||||
if(IsWeird(m) || IsWeird(n)){
|
||||
/* BUG: should trap if not masked */
|
||||
return V|C;
|
||||
}
|
||||
rn = *n;
|
||||
rm = *m;
|
||||
fpiround(&rn);
|
||||
fpiround(&rm);
|
||||
i = fpicmp(&rn, &rm);
|
||||
if(i > 0)
|
||||
return C;
|
||||
else if(i == 0)
|
||||
return C|Z;
|
||||
else
|
||||
return N;
|
||||
}
|
||||
|
||||
static void
|
||||
fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
mem = (void*)ea;
|
||||
(*f)(&FR(ufp, d), mem);
|
||||
if(fpemudebug)
|
||||
print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp)
|
||||
{
|
||||
Internal tmp;
|
||||
void *mem;
|
||||
|
||||
mem = (void*)ea;
|
||||
tmp = FR(ufp, s);
|
||||
if(fpemudebug)
|
||||
print("MOV%c F%d,#%lux\n", n==8? 'D': 'F', s, ea);
|
||||
(*f)(mem, &tmp);
|
||||
}
|
||||
|
||||
static int
|
||||
condok(int cc, int c)
|
||||
{
|
||||
switch(c){
|
||||
case 0: /* Z set */
|
||||
return cc&Z;
|
||||
case 1: /* Z clear */
|
||||
return (cc&Z) == 0;
|
||||
case 2: /* C set */
|
||||
return cc&C;
|
||||
case 3: /* C clear */
|
||||
return (cc&C) == 0;
|
||||
case 4: /* N set */
|
||||
return cc&N;
|
||||
case 5: /* N clear */
|
||||
return (cc&N) == 0;
|
||||
case 6: /* V set */
|
||||
return cc&V;
|
||||
case 7: /* V clear */
|
||||
return (cc&V) == 0;
|
||||
case 8: /* C set and Z clear */
|
||||
return cc&C && (cc&Z) == 0;
|
||||
case 9: /* C clear or Z set */
|
||||
return (cc&C) == 0 || cc&Z;
|
||||
case 10: /* N set and V set, or N clear and V clear */
|
||||
return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
|
||||
case 11: /* N set and V clear, or N clear and V set */
|
||||
return (cc&(N|V))==N || (cc&(N|V))==V;
|
||||
case 12: /* Z clear, and either N set and V set or N clear and V clear */
|
||||
return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
|
||||
case 13: /* Z set, or N set and V clear or N clear and V set */
|
||||
return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
|
||||
case 14: /* always */
|
||||
return 1;
|
||||
case 15: /* never (reserved) */
|
||||
return 0;
|
||||
}
|
||||
return 0; /* not reached */
|
||||
}
|
||||
|
||||
static void
|
||||
unimp(ulong pc, ulong op)
|
||||
{
|
||||
char buf[60];
|
||||
|
||||
snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op);
|
||||
if(fpemudebug)
|
||||
print("FPE: %s\n", buf);
|
||||
error(buf);
|
||||
/* no return */
|
||||
}
|
||||
|
||||
static void
|
||||
fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
|
||||
{
|
||||
int rn, rd, tag, o;
|
||||
long off;
|
||||
ulong ea;
|
||||
Internal tmp, *fm, *fn;
|
||||
|
||||
/* note: would update fault status here if we noted numeric exceptions */
|
||||
|
||||
/*
|
||||
* LDF, STF; 10.1.1
|
||||
*/
|
||||
if(((op>>25)&7) == 6){
|
||||
if(op & (1<<22))
|
||||
unimp(pc, op); /* packed or extended */
|
||||
rn = (op>>16)&0xF;
|
||||
off = (op&0xFF)<<2;
|
||||
if((op & (1<<23)) == 0)
|
||||
off = -off;
|
||||
ea = REG(ur, rn);
|
||||
if(rn == REGPC)
|
||||
ea += 8;
|
||||
if(op & (1<<24))
|
||||
ea += off;
|
||||
rd = (op>>12)&7;
|
||||
if(op & (1<<20)){
|
||||
if(op & (1<<15))
|
||||
fld(fpid2i, rd, ea, 8, ufp);
|
||||
else
|
||||
fld(fpis2i, rd, ea, 4, ufp);
|
||||
}else{
|
||||
if(op & (1<<15))
|
||||
fst(fpii2d, ea, rd, 8, ufp);
|
||||
else
|
||||
fst(fpii2s, ea, rd, 4, ufp);
|
||||
}
|
||||
if((op & (1<<24)) == 0)
|
||||
ea += off;
|
||||
if(op & (1<<21))
|
||||
REG(ur, rn) = ea;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPRT/transfer, 10.3
|
||||
*/
|
||||
if(op & (1<<4)){
|
||||
rd = (op>>12) & 0xF;
|
||||
|
||||
/*
|
||||
* compare, 10.3.1
|
||||
*/
|
||||
if(rd == 15 && op & (1<<20)){
|
||||
rn = (op>>16)&7;
|
||||
fn = &FR(ufp, rn);
|
||||
if(op & (1<<3)){
|
||||
fm = &fpconst[op&7];
|
||||
tag = 'C';
|
||||
}else{
|
||||
fm = &FR(ufp, op&7);
|
||||
tag = 'F';
|
||||
}
|
||||
switch((op>>21)&7){
|
||||
default:
|
||||
unimp(pc, op);
|
||||
case 4: /* CMF: Fn :: Fm */
|
||||
case 6: /* CMFE: Fn :: Fm (with exception) */
|
||||
ur->psr &= ~(N|C|Z|V);
|
||||
ur->psr |= fcmp(fn, fm);
|
||||
break;
|
||||
case 5: /* CNF: Fn :: -Fm */
|
||||
case 7: /* CNFE: Fn :: -Fm (with exception) */
|
||||
tmp = *fm;
|
||||
tmp.s ^= 1;
|
||||
ur->psr &= ~(N|C|Z|V);
|
||||
ur->psr |= fcmp(fn, &tmp);
|
||||
break;
|
||||
}
|
||||
if(fpemudebug)
|
||||
print("CMPF %c%d,F%ld =%lux\n", tag, rn, op&7, ur->psr>>28);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* other transfer, 10.3
|
||||
*/
|
||||
switch((op>>20)&0xF){
|
||||
default:
|
||||
unimp(pc, op);
|
||||
case 0: /* FLT */
|
||||
rn = (op>>16) & 7;
|
||||
fpiw2i(&FR(ufp, rn), ®(ur, rd));
|
||||
if(fpemudebug)
|
||||
print("MOVW[FD] R%d, F%d\n", rd, rn);
|
||||
break;
|
||||
case 1: /* FIX */
|
||||
if(op & (1<<3))
|
||||
unimp(pc, op);
|
||||
rn = op & 7;
|
||||
tmp = FR(ufp, rn);
|
||||
fpii2w(®(ur, rd), &tmp);
|
||||
if(fpemudebug)
|
||||
print("MOV[FD]W F%d, R%d =%ld\n", rn, rd, REG(ur, rd));
|
||||
break;
|
||||
case 2: /* FPSR := Rd */
|
||||
ufp->status = REG(ur, rd);
|
||||
if(fpemudebug)
|
||||
print("MOVW R%d, FPSR\n", rd);
|
||||
break;
|
||||
case 3: /* Rd := FPSR */
|
||||
REG(ur, rd) = ufp->status;
|
||||
if(fpemudebug)
|
||||
print("MOVW FPSR, R%d\n", rd);
|
||||
break;
|
||||
case 4: /* FPCR := Rd */
|
||||
ufp->control = REG(ur, rd);
|
||||
if(fpemudebug)
|
||||
print("MOVW R%d, FPCR\n", rd);
|
||||
break;
|
||||
case 5: /* Rd := FPCR */
|
||||
REG(ur, rd) = ufp->control;
|
||||
if(fpemudebug)
|
||||
print("MOVW FPCR, R%d\n", rd);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* arithmetic
|
||||
*/
|
||||
|
||||
if(op & (1<<3)){ /* constant */
|
||||
fm = &fpconst[op&7];
|
||||
tag = 'C';
|
||||
}else{
|
||||
fm = &FR(ufp, op&7);
|
||||
tag = 'F';
|
||||
}
|
||||
rd = (op>>12)&7;
|
||||
o = (op>>20)&0xF;
|
||||
if(op & (1<<15)){ /* monadic */
|
||||
FP1 *fp;
|
||||
fp = &optab1[o];
|
||||
if(fp->f == nil)
|
||||
unimp(pc, op);
|
||||
if(fpemudebug)
|
||||
print("%s %c%ld,F%d\n", fp->name, tag, op&7, rd);
|
||||
(*fp->f)(fm, &FR(ufp, rd));
|
||||
} else {
|
||||
FP2 *fp;
|
||||
fp = &optab2[o];
|
||||
if(fp->f == nil)
|
||||
unimp(pc, op);
|
||||
rn = (op>>16)&7;
|
||||
if(fpemudebug)
|
||||
print("%s %c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd);
|
||||
(*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
casemu(ulong pc, ulong op, Ureg *ur)
|
||||
{
|
||||
ulong *rp, ro, rn, *rd;
|
||||
|
||||
USED(pc);
|
||||
|
||||
rp = (ulong*)ur;
|
||||
ro = rp[op>>16 & 0x7];
|
||||
rn = rp[op>>0 & 0x7];
|
||||
rd = rp + (op>>12 & 0x7);
|
||||
rp = (ulong*)*rd;
|
||||
validaddr((ulong)rp, 4, 1);
|
||||
splhi();
|
||||
if(*rd = (*rp == ro))
|
||||
*rp = rn;
|
||||
spllo();
|
||||
}
|
||||
|
||||
int ldrexvalid;
|
||||
|
||||
void
|
||||
ldrex(ulong pc, ulong op, Ureg *ur)
|
||||
{
|
||||
ulong *rp, *rd, *addr;
|
||||
|
||||
USED(pc);
|
||||
|
||||
rp = (ulong*)ur;
|
||||
rd = rp + (op>>16 & 0x7);
|
||||
addr = (ulong*)*rd;
|
||||
validaddr((ulong)addr, 4, 0);
|
||||
ldrexvalid = 1;
|
||||
rp[op>>12 & 0x7] = *addr;
|
||||
if(fpemudebug)
|
||||
print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux",
|
||||
op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]);
|
||||
}
|
||||
|
||||
void
|
||||
strex(ulong pc, ulong op, Ureg *ur)
|
||||
{
|
||||
ulong *rp, rn, *rd, *addr;
|
||||
|
||||
USED(pc);
|
||||
|
||||
rp = (ulong*)ur;
|
||||
rd = rp + (op>>16 & 0x7);
|
||||
rn = rp[op>>0 & 0x7];
|
||||
addr = (ulong*)*rd;
|
||||
validaddr((ulong)addr, 4, 1);
|
||||
splhi();
|
||||
if(ldrexvalid){
|
||||
if(fpemudebug)
|
||||
print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux",
|
||||
op>>16 & 0x7, addr, op>>0 & 0x7, rn);
|
||||
*addr = rn;
|
||||
ldrexvalid = 0;
|
||||
rp[op>>12 & 0x7] = 0;
|
||||
}else{
|
||||
if(fpemudebug)
|
||||
print("strex invalid, r%ld = 1", op>>16 & 0x7);
|
||||
rp[op>>12 & 0x7] = 1;
|
||||
}
|
||||
spllo();
|
||||
}
|
||||
|
||||
struct {
|
||||
ulong opc;
|
||||
ulong mask;
|
||||
void (*f)(ulong, ulong, Ureg*);
|
||||
} specialopc[] = {
|
||||
{ 0x01900f9f, 0x0ff00fff, ldrex },
|
||||
{ 0x01800f90, 0x0ff00ff0, strex },
|
||||
{ 0x0ed00100, 0x0ef08100, casemu },
|
||||
{ 0x00000000, 0x00000000, nil }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* returns the number of FP instructions emulated
|
||||
*/
|
||||
int
|
||||
fpiarm(Ureg *ur)
|
||||
{
|
||||
ulong op, o;
|
||||
FPsave *ufp;
|
||||
int i, n;
|
||||
|
||||
if (up == nil)
|
||||
panic("fpiarm not in a process");
|
||||
ufp = &up->fpsave;
|
||||
/* because all the state is in the proc structure,
|
||||
* it need not be saved/restored
|
||||
*/
|
||||
if(up->fpstate != FPactive) {
|
||||
// assert(sizeof(Internal) == sizeof(ufp->regs[0]));
|
||||
up->fpstate = FPactive;
|
||||
ufp->control = 0;
|
||||
ufp->status = (0x01<<28)|(1<<12); /* software emulation, alternative C flag */
|
||||
for(n = 0; n < 8; n++)
|
||||
FR(ufp, n) = fpconst[0];
|
||||
}
|
||||
for(n=0; ;n++){
|
||||
if(fpemudebug)
|
||||
print("0x%8.8lux ", ur->pc);
|
||||
validaddr(ur->pc, 4, 0);
|
||||
op = *(ulong*)(ur->pc);
|
||||
o = (op>>24) & 0xF;
|
||||
if(condok(ur->psr, op>>28)){
|
||||
for(i = 0; specialopc[i].f; i++)
|
||||
if((op & specialopc[i].mask) == specialopc[i].opc)
|
||||
break;
|
||||
if(specialopc[i].f)
|
||||
specialopc[i].f(ur->pc, op, ur);
|
||||
else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
|
||||
break;
|
||||
else
|
||||
fpemu(ur->pc, op, ur, ufp);
|
||||
}else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
|
||||
break;
|
||||
ur->pc += 4;
|
||||
}
|
||||
if(fpemudebug) print("\n");
|
||||
return n;
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
#include "fpi.h"
|
||||
|
||||
/*
|
||||
* the following routines depend on memory format, not the machine
|
||||
*/
|
||||
|
||||
void
|
||||
fpis2i(Internal *i, void *v)
|
||||
{
|
||||
Single *s = v;
|
||||
|
||||
i->s = (*s & 0x80000000) ? 1: 0;
|
||||
if((*s & ~0x80000000) == 0){
|
||||
SetZero(i);
|
||||
return;
|
||||
}
|
||||
i->e = ((*s>>23) & 0x00FF) - SingleExpBias + ExpBias;
|
||||
i->h = (*s & 0x007FFFFF)<<(1+NGuardBits);
|
||||
i->l = 0;
|
||||
if(i->e)
|
||||
i->h |= HiddenBit;
|
||||
else
|
||||
i->e++;
|
||||
}
|
||||
|
||||
void
|
||||
fpid2i(Internal *i, void *v)
|
||||
{
|
||||
Double *d = v;
|
||||
|
||||
i->s = (d->h & 0x80000000) ? 1: 0;
|
||||
i->e = (d->h>>20) & 0x07FF;
|
||||
i->h = ((d->h & 0x000FFFFF)<<(4+NGuardBits))|((d->l>>25) & 0x7F);
|
||||
i->l = (d->l & 0x01FFFFFF)<<NGuardBits;
|
||||
if(i->e)
|
||||
i->h |= HiddenBit;
|
||||
else
|
||||
i->e++;
|
||||
}
|
||||
|
||||
void
|
||||
fpiw2i(Internal *i, void *v)
|
||||
{
|
||||
Word w, word = *(Word*)v;
|
||||
short e;
|
||||
|
||||
if(word < 0){
|
||||
i->s = 1;
|
||||
word = -word;
|
||||
}
|
||||
else
|
||||
i->s = 0;
|
||||
if(word == 0){
|
||||
SetZero(i);
|
||||
return;
|
||||
}
|
||||
if(word > 0){
|
||||
for (e = 0, w = word; w; w >>= 1, e++)
|
||||
;
|
||||
} else
|
||||
e = 32;
|
||||
if(e > FractBits){
|
||||
i->h = word>>(e - FractBits);
|
||||
i->l = (word & ((1<<(e - FractBits)) - 1))<<(2*FractBits - e);
|
||||
}
|
||||
else {
|
||||
i->h = word<<(FractBits - e);
|
||||
i->l = 0;
|
||||
}
|
||||
i->e = (e - 1) + ExpBias;
|
||||
}
|
||||
|
||||
void
|
||||
fpii2s(void *v, Internal *i)
|
||||
{
|
||||
short e;
|
||||
Single *s = (Single*)v;
|
||||
|
||||
fpiround(i);
|
||||
if(i->h & HiddenBit)
|
||||
i->h &= ~HiddenBit;
|
||||
else
|
||||
i->e--;
|
||||
*s = i->s ? 0x80000000: 0;
|
||||
e = i->e;
|
||||
if(e < ExpBias){
|
||||
if(e <= (ExpBias - SingleExpBias))
|
||||
return;
|
||||
e = SingleExpBias - (ExpBias - e);
|
||||
}
|
||||
else if(e >= (ExpBias + (SingleExpMax-SingleExpBias))){
|
||||
*s |= SingleExpMax<<23;
|
||||
return;
|
||||
}
|
||||
else
|
||||
e = SingleExpBias + (e - ExpBias);
|
||||
*s |= (e<<23)|(i->h>>(1+NGuardBits));
|
||||
}
|
||||
|
||||
void
|
||||
fpii2d(void *v, Internal *i)
|
||||
{
|
||||
Double *d = (Double*)v;
|
||||
|
||||
fpiround(i);
|
||||
if(i->h & HiddenBit)
|
||||
i->h &= ~HiddenBit;
|
||||
else
|
||||
i->e--;
|
||||
i->l = ((i->h & GuardMask)<<25)|(i->l>>NGuardBits);
|
||||
i->h >>= NGuardBits;
|
||||
d->h = i->s ? 0x80000000: 0;
|
||||
d->h |= (i->e<<20)|((i->h & 0x00FFFFFF)>>4);
|
||||
d->l = (i->h<<28)|i->l;
|
||||
}
|
||||
|
||||
void
|
||||
fpii2w(Word *word, Internal *i)
|
||||
{
|
||||
Word w;
|
||||
short e;
|
||||
|
||||
fpiround(i);
|
||||
e = (i->e - ExpBias) + 1;
|
||||
if(e <= 0)
|
||||
w = 0;
|
||||
else if(e > 31)
|
||||
w = 0x7FFFFFFF;
|
||||
else if(e > FractBits)
|
||||
w = (i->h<<(e - FractBits))|(i->l>>(2*FractBits - e));
|
||||
else
|
||||
w = i->h>>(FractBits-e);
|
||||
if(i->s)
|
||||
w = -w;
|
||||
*word = w;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
double gamma = 1.6;
|
||||
|
||||
int
|
||||
remap5(int i)
|
||||
{
|
||||
double v;
|
||||
|
||||
v = (double)i/31.0;
|
||||
return 31.0*pow(v, gamma);
|
||||
}
|
||||
|
||||
int
|
||||
remap6(int i)
|
||||
{
|
||||
double v;
|
||||
|
||||
v = (double)i/63.0;
|
||||
return 63.0*pow(v, gamma);
|
||||
}
|
||||
|
||||
int
|
||||
remap(int i)
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
b = i & 0x1F;
|
||||
g = (i>>5) & 0x3F;
|
||||
r = (i>>11) & 0x1F;
|
||||
return (remap5(r)<<11) | (remap6(g)<<5) | (remap5(b)<<0);
|
||||
}
|
||||
|
||||
void
|
||||
main(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("/* gamma = %.2f */\n", gamma);
|
||||
printf("ushort gamma[65536] = {\n");
|
||||
for(i=0; i<65536; i++){
|
||||
if((i%8) == 0)
|
||||
printf("\t");
|
||||
printf("0x%.4x, ", remap(i));
|
||||
if((i%8) == 7)
|
||||
printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +0,0 @@
|
|||
TEXT _main(SB),$8
|
||||
MOVW $setR12(SB), R12 /* load the SB */
|
||||
MOVW $boot(SB), R0
|
||||
|
||||
ADD $12, R13, R1 /* get a pointer to 0(FP) */
|
||||
|
||||
MOVW R0, 4(R13)
|
||||
MOVW R1, 8(R13)
|
||||
|
||||
BL startboot(SB)
|
||||
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
/*
|
||||
* Definitions for IO devices. Used only in C.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
/* hardware counter frequency */
|
||||
ClockFreq= 3686400,
|
||||
};
|
||||
|
||||
/*
|
||||
* IRQ's defined by SA1100
|
||||
*/
|
||||
enum
|
||||
{
|
||||
IRQgpio0= 0,
|
||||
IRQgpio1= 1,
|
||||
IRQgpio2= 2,
|
||||
IRQgpio3= 3,
|
||||
IRQgpio4= 4,
|
||||
IRQgpio5= 5,
|
||||
IRQgpio6= 6,
|
||||
IRQgpio7= 7,
|
||||
IRQgpio8= 8,
|
||||
IRQgpio9= 9,
|
||||
IRQgpio10= 10,
|
||||
IRQgpiohi= 11,
|
||||
IRQlcd= 12,
|
||||
IRQudc= 13,
|
||||
IRQuart1b= 15,
|
||||
IRQuart2= 16,
|
||||
IRQuart3= 17,
|
||||
IRQmcp= 18,
|
||||
IRQssp= 19,
|
||||
IRQdma0= 20,
|
||||
IRQdma1= 21,
|
||||
IRQdma2= 22,
|
||||
IRQdma3= 23,
|
||||
IRQdma4= 24,
|
||||
IRQdma5= 25,
|
||||
IRQtimer0= 26,
|
||||
IRQtimer1= 27,
|
||||
IRQtimer2= 28,
|
||||
IRQtimer3= 29,
|
||||
IRQsecond= 30,
|
||||
IRQrtc= 31,
|
||||
};
|
||||
|
||||
/*
|
||||
* GPIO lines (signal names from compaq document). _i indicates input
|
||||
* and _o output.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
GPIO_PWR_ON_i= 1<<0, /* power button */
|
||||
GPIO_UP_IRQ_i= 1<<1, /* microcontroller interrupts */
|
||||
GPIO_LDD8_o= 1<<2, /* LCD data 8-15 */
|
||||
GPIO_LDD9_o= 1<<3,
|
||||
GPIO_LDD10_o= 1<<4,
|
||||
GPIO_LDD11_o= 1<<5,
|
||||
GPIO_LDD12_o= 1<<6,
|
||||
GPIO_LDD13_o= 1<<7,
|
||||
GPIO_LDD14_o= 1<<8,
|
||||
GPIO_LDD15_o= 1<<9,
|
||||
GPIO_CARD_IND1_i= 1<<10, /* card inserted in PCMCIA socket 1 */
|
||||
GPIO_CARD_IRQ1_i= 1<<11, /* PCMCIA socket 1 interrupt */
|
||||
GPIO_CLK_SET0_o= 1<<12, /* clock selects for audio codec */
|
||||
GPIO_CLK_SET1_o= 1<<13,
|
||||
GPIO_L3_SDA_io= 1<<14, /* UDA1341 interface */
|
||||
GPIO_L3_MODE_o= 1<<15,
|
||||
GPIO_L3_SCLK_o= 1<<16,
|
||||
GPIO_CARD_IND0_i= 1<<17, /* card inserted in PCMCIA socket 0 */
|
||||
GPIO_KEY_ACT_i= 1<<18, /* hot key from cradle */
|
||||
GPIO_SYS_CLK_i= 1<<19, /* clock from codec */
|
||||
GPIO_BAT_FAULT_i= 1<<20, /* battery fault */
|
||||
GPIO_CARD_IRQ0_i= 1<<21, /* PCMCIA socket 0 interrupt */
|
||||
GPIO_LOCK_i= 1<<22, /* expansion pack lock/unlock */
|
||||
GPIO_COM_DCD_i= 1<<23, /* DCD from UART3 */
|
||||
GPIO_OPT_IRQ_i= 1<<24, /* expansion pack IRQ */
|
||||
GPIO_COM_CTS_i= 1<<25, /* CTS from UART3 */
|
||||
GPIO_COM_RTS_o= 1<<26, /* RTS to UART3 */
|
||||
GPIO_OPT_IND_i= 1<<27, /* expansion pack inserted */
|
||||
|
||||
/* Peripheral Unit GPIO pin assignments: alternate functions */
|
||||
GPIO_SSP_TXD_o= 1<<10, /* SSP Transmit Data */
|
||||
GPIO_SSP_RXD_i= 1<<11, /* SSP Receive Data */
|
||||
GPIO_SSP_SCLK_o= 1<<12, /* SSP Sample CLocK */
|
||||
GPIO_SSP_SFRM_o= 1<<13, /* SSP Sample FRaMe */
|
||||
/* ser. port 1: */
|
||||
GPIO_UART_TXD_o= 1<<14, /* UART Transmit Data */
|
||||
GPIO_UART_RXD_i= 1<<15, /* UART Receive Data */
|
||||
GPIO_SDLC_SCLK_io= 1<<16, /* SDLC Sample CLocK (I/O) */
|
||||
GPIO_SDLC_AAF_o= 1<<17, /* SDLC Abort After Frame */
|
||||
GPIO_UART_SCLK1_i= 1<<18, /* UART Sample CLocK 1 */
|
||||
/* ser. port 4: */
|
||||
GPIO_SSP_CLK_i= 1<<19, /* SSP external CLocK */
|
||||
/* ser. port 3: */
|
||||
GPIO_UART_SCLK3_i= 1<<20, /* UART Sample CLocK 3 */
|
||||
/* ser. port 4: */
|
||||
GPIO_MCP_CLK_i= 1<<21, /* MCP CLocK */
|
||||
/* test controller: */
|
||||
GPIO_TIC_ACK_o= 1<<21, /* TIC ACKnowledge */
|
||||
GPIO_MBGNT_o= 1<<21, /* Memory Bus GraNT */
|
||||
GPIO_TREQA_i= 1<<22, /* TIC REQuest A */
|
||||
GPIO_MBREQ_i= 1<<22, /* Memory Bus REQuest */
|
||||
GPIO_TREQB_i= 1<<23, /* TIC REQuest B */
|
||||
GPIO_1Hz_o= 1<<25, /* 1 Hz clock */
|
||||
GPIO_RCLK_o= 1<<26, /* internal (R) CLocK (O, fcpu/2) */
|
||||
GPIO_32_768kHz_o= 1<<27, /* 32.768 kHz clock (O, RTC) */
|
||||
};
|
||||
|
||||
/*
|
||||
* types of interrupts
|
||||
*/
|
||||
enum
|
||||
{
|
||||
GPIOrising,
|
||||
GPIOfalling,
|
||||
GPIOboth,
|
||||
IRQ,
|
||||
};
|
||||
|
||||
/* hardware registers */
|
||||
typedef struct Uartregs Uartregs;
|
||||
struct Uartregs
|
||||
{
|
||||
ulong ctl[4];
|
||||
ulong dummya;
|
||||
ulong data;
|
||||
ulong dummyb;
|
||||
ulong status[2];
|
||||
};
|
||||
extern Uartregs *uart3regs;
|
||||
extern Uartregs *uart1regs;
|
||||
|
||||
/* general purpose I/O lines control registers */
|
||||
typedef struct GPIOregs GPIOregs;
|
||||
struct GPIOregs
|
||||
{
|
||||
ulong level; /* 1 == high */
|
||||
ulong direction; /* 1 == output */
|
||||
ulong set; /* a 1 sets the bit, 0 leaves it alone */
|
||||
ulong clear; /* a 1 clears the bit, 0 leaves it alone */
|
||||
ulong rising; /* rising edge detect enable */
|
||||
ulong falling; /* falling edge detect enable */
|
||||
ulong edgestatus; /* writing a 1 bit clears */
|
||||
ulong altfunc; /* turn on alternate function for any set bits */
|
||||
};
|
||||
|
||||
extern GPIOregs *gpioregs;
|
||||
|
||||
/* extra general purpose I/O bits, output only */
|
||||
enum
|
||||
{
|
||||
EGPIO_prog_flash= 1<<0,
|
||||
EGPIO_pcmcia_reset= 1<<1,
|
||||
EGPIO_exppack_reset= 1<<2,
|
||||
EGPIO_codec_reset= 1<<3,
|
||||
EGPIO_exp_nvram_power= 1<<4,
|
||||
EGPIO_exp_full_power= 1<<5,
|
||||
EGPIO_lcd_3v= 1<<6,
|
||||
EGPIO_rs232_power= 1<<7,
|
||||
EGPIO_lcd_ic_power= 1<<8,
|
||||
EGPIO_ir_power= 1<<9,
|
||||
EGPIO_audio_power= 1<<10,
|
||||
EGPIO_audio_ic_power= 1<<11,
|
||||
EGPIO_audio_mute= 1<<12,
|
||||
EGPIO_fir= 1<<13, /* not set is sir */
|
||||
EGPIO_lcd_5v= 1<<14,
|
||||
EGPIO_lcd_9v= 1<<15,
|
||||
};
|
||||
extern ulong *egpioreg;
|
||||
|
||||
/* Peripheral pin controller registers */
|
||||
typedef struct PPCregs PPCregs;
|
||||
struct PPCregs {
|
||||
ulong direction;
|
||||
ulong state;
|
||||
ulong assignment;
|
||||
ulong sleepdir;
|
||||
ulong flags;
|
||||
};
|
||||
extern PPCregs *ppcregs;
|
||||
|
||||
/* Synchronous Serial Port controller registers */
|
||||
typedef struct SSPregs SSPregs;
|
||||
struct SSPregs {
|
||||
ulong control0;
|
||||
ulong control1;
|
||||
ulong dummy0;
|
||||
ulong data;
|
||||
ulong dummy1;
|
||||
ulong status;
|
||||
};
|
||||
extern SSPregs *sspregs;
|
||||
|
||||
/* Multimedia Communications Port controller registers */
|
||||
typedef struct MCPregs MCPregs;
|
||||
struct MCPregs {
|
||||
ulong control0;
|
||||
ulong reserved0;
|
||||
ulong data0;
|
||||
ulong data1;
|
||||
ulong data2;
|
||||
ulong reserved1;
|
||||
ulong status;
|
||||
ulong reserved[11];
|
||||
ulong control1;
|
||||
};
|
||||
extern MCPregs *mcpregs;
|
||||
|
||||
/*
|
||||
* memory configuration
|
||||
*/
|
||||
enum
|
||||
{
|
||||
/* bit shifts for pcmcia access time counters */
|
||||
MECR_io0= 0,
|
||||
MECR_attr0= 5,
|
||||
MECR_mem0= 10,
|
||||
MECR_fast0= 11,
|
||||
MECR_io1= MECR_io0+16,
|
||||
MECR_attr1= MECR_attr0+16,
|
||||
MECR_mem1= MECR_mem0+16,
|
||||
MECR_fast1= MECR_fast0+16,
|
||||
|
||||
REFR_kapd= 29,
|
||||
REFR_eapd= 28,
|
||||
REFR_k1db2= 22,
|
||||
REFR_slfrsh= 31,
|
||||
};
|
||||
|
||||
typedef struct MemConfRegs MemConfRegs;
|
||||
struct MemConfRegs
|
||||
{
|
||||
ulong mdcnfg; /* 0x00 dram */
|
||||
ulong mdcas00; /* 0x04 dram banks 0/1 */
|
||||
ulong mdcas01; /* 0x08 */
|
||||
ulong mdcas02; /* 0x0c */
|
||||
ulong msc0; /* 0x10 static */
|
||||
ulong msc1; /* 0x14 */
|
||||
ulong mecr; /* 0x18 pcmcia */
|
||||
ulong mdrefr; /* 0x1c dram refresh */
|
||||
ulong mdcas20; /* 0x20 dram banks 2/3 */
|
||||
ulong mdcas21; /* 0x24 */
|
||||
ulong mdcas22; /* 0x28 */
|
||||
ulong msc2; /* 0x2c static */
|
||||
ulong smcnfg; /* 0x30 SMROM config */
|
||||
};
|
||||
extern MemConfRegs *memconfregs;
|
||||
|
||||
/*
|
||||
* power management
|
||||
*/
|
||||
|
||||
/* Power management ops */
|
||||
|
||||
typedef struct PowerRegs PowerRegs;
|
||||
struct PowerRegs
|
||||
{
|
||||
ulong pmcr; /* 0x0 Power manager control register */
|
||||
ulong pssr; /* 0x4 Power manager sleep status register */
|
||||
ulong pspr; /* 0x8 Power manager scratch pad register */
|
||||
ulong pwer; /* 0xc Power manager wakeup enable register */
|
||||
ulong pcfr; /* 0x10 Power manager general configuration register */
|
||||
ulong ppcr; /* 0x14 Power manager PPL configuration register */
|
||||
ulong pgsr; /* 0x18 Power manager GPIO sleep state register */
|
||||
ulong posr; /* 0x1c Power manager oscillator status register */
|
||||
};
|
||||
extern PowerRegs *powerregs;
|
||||
|
||||
/*
|
||||
* reset controller
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
RCSR_hwr = 0x00000001, /* hw reset */
|
||||
RCSR_swr = 0x00000002, /* sw reset */
|
||||
RCSR_wdr = 0x00000004, /* watch dog */
|
||||
RCSR_smr = 0x00000008, /* sleep mode reset */
|
||||
};
|
||||
|
||||
typedef struct ResetRegs ResetRegs;
|
||||
struct ResetRegs
|
||||
{
|
||||
ulong rsrr; /* reset controller software reset register */
|
||||
ulong rcsr; /* reset controller status register */
|
||||
};
|
||||
extern ResetRegs *resetregs;
|
||||
|
||||
typedef struct OSTimerRegs OSTimerRegs;
|
||||
struct OSTimerRegs
|
||||
{
|
||||
ulong osmr[4]; /* match registers */
|
||||
ulong oscr; /* counter register */
|
||||
ulong ossr; /* status register */
|
||||
ulong ower; /* watchdog enable register */
|
||||
ulong oier; /* timer interrupt enable register */
|
||||
};
|
||||
extern OSTimerRegs* timerregs;
|
||||
|
||||
typedef struct Intrregs Intrregs;
|
||||
struct Intrregs
|
||||
{
|
||||
ulong icip; /* pending IRQs */
|
||||
ulong icmr; /* IRQ mask */
|
||||
ulong iclr; /* IRQ if bit == 0, FRIQ if 1 */
|
||||
ulong iccr; /* control register */
|
||||
ulong icfp; /* pending FIQs */
|
||||
ulong dummy1[3];
|
||||
ulong icpr; /* pending interrupts */
|
||||
};
|
||||
extern Intrregs *intrregs;
|
||||
|
||||
typedef struct Gpclkregs Gpclkregs;
|
||||
struct Gpclkregs
|
||||
{
|
||||
ulong r0;
|
||||
ulong r1;
|
||||
ulong dummya;
|
||||
ulong r2;
|
||||
ulong r3;
|
||||
};
|
||||
extern Gpclkregs *gpclkregs;
|
||||
|
||||
/*
|
||||
* Dont use this on bitsy drivers.
|
||||
* This is for compat with code compiled
|
||||
* from the ../pc directory
|
||||
*/
|
||||
|
||||
typedef struct Pcidev Pcidev;
|
||||
typedef struct ISAConf ISAConf;
|
||||
struct Pcidev { int dummy; };
|
||||
struct ISAConf{ int port; int irq; };
|
||||
int pcmspecial(char*, ISAConf*);
|
|
@ -1,857 +0,0 @@
|
|||
#include "mem.h"
|
||||
|
||||
/*
|
||||
* Entered here from Compaq's bootldr with MMU disabled.
|
||||
*/
|
||||
TEXT _start(SB), $-4
|
||||
MOVW $setR12(SB), R12 /* load the SB */
|
||||
_main:
|
||||
/* SVC mode, interrupts disabled */
|
||||
MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
|
||||
MOVW R1, CPSR
|
||||
|
||||
/* disable the MMU */
|
||||
MOVW $0x130, R1
|
||||
MCR CpMMU, 0, R1, C(CpControl), C(0x0)
|
||||
|
||||
/* flush caches */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
|
||||
/* drain prefetch */
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
|
||||
/* drain write buffer */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
|
||||
|
||||
MOVW $(MACHADDR+4*BY2PG), R13 /* stack */
|
||||
SUB $4, R13 /* link */
|
||||
BL main(SB)
|
||||
BL exit(SB)
|
||||
/* we shouldn't get here */
|
||||
_mainloop:
|
||||
B _mainloop
|
||||
BL _div(SB) /* hack to get _div etc loaded */
|
||||
|
||||
/* flush tlb's */
|
||||
TEXT mmuinvalidate(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x7)
|
||||
RET
|
||||
|
||||
/* flush tlb's */
|
||||
TEXT mmuinvalidateaddr(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x6), 1
|
||||
RET
|
||||
|
||||
/* write back and invalidate i and d caches */
|
||||
TEXT cacheflush(SB), $-4
|
||||
/* splhi */
|
||||
MOVW CPSR, R3
|
||||
ORR $(PsrDirq), R3, R1
|
||||
MOVW R1, CPSR
|
||||
|
||||
/* write back any dirty data */
|
||||
MOVW $0xe0000000,R0
|
||||
ADD $(8*1024),R0,R1
|
||||
_cfloop:
|
||||
MOVW.P 32(R0),R2
|
||||
CMP.S R0,R1
|
||||
BGE _cfloop
|
||||
|
||||
/* drain write buffer and invalidate i cache contents */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x5), 0
|
||||
|
||||
/* drain prefetch */
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
|
||||
/* splx */
|
||||
MOVW R3, CPSR
|
||||
RET
|
||||
|
||||
/* write back d cache */
|
||||
TEXT cachewb(SB), $-4
|
||||
/* write back any dirty data */
|
||||
_cachewb:
|
||||
MOVW $0xe0000000,R0
|
||||
ADD $(8*1024),R0,R1
|
||||
_cwbloop:
|
||||
MOVW.P 32(R0),R2
|
||||
CMP.S R0,R1
|
||||
BGE _cwbloop
|
||||
|
||||
/* drain write buffer */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
|
||||
RET
|
||||
|
||||
/* write back a single cache line */
|
||||
TEXT cachewbaddr(SB), $-4
|
||||
BIC $31,R0
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
|
||||
B _wbflush
|
||||
|
||||
/* write back a region of cache lines */
|
||||
TEXT cachewbregion(SB), $-4
|
||||
MOVW 4(FP),R1
|
||||
CMP.S $(4*1024),R1
|
||||
BGT _cachewb
|
||||
ADD R0,R1
|
||||
BIC $31,R0
|
||||
_cwbrloop:
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
|
||||
ADD $32,R0
|
||||
CMP.S R0,R1
|
||||
BGT _cwbrloop
|
||||
B _wbflush
|
||||
|
||||
/* invalidate the dcache */
|
||||
TEXT dcacheinvalidate(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x6)
|
||||
RET
|
||||
|
||||
/* invalidate the icache */
|
||||
TEXT icacheinvalidate(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x9)
|
||||
RET
|
||||
|
||||
/* drain write buffer */
|
||||
TEXT wbflush(SB), $-4
|
||||
_wbflush:
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
|
||||
RET
|
||||
|
||||
/* return cpu id */
|
||||
TEXT getcpuid(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpCPUID), C(0x0)
|
||||
RET
|
||||
|
||||
/* return fault status */
|
||||
TEXT getfsr(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpFSR), C(0x0)
|
||||
RET
|
||||
|
||||
/* return mmu control register */
|
||||
TEXT getcontrol(SB), $-4
|
||||
SUB R0, R0
|
||||
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
RET
|
||||
|
||||
/* return mmu dac register */
|
||||
TEXT getdac(SB), $-4
|
||||
SUB R0, R0
|
||||
MRC CpMMU, 0, R0, C(CpDAC), C(0x0)
|
||||
RET
|
||||
|
||||
/* return mmu ttb register */
|
||||
TEXT getttb(SB), $-4
|
||||
SUB R0, R0
|
||||
MRC CpMMU, 0, R0, C(CpTTB), C(0x0)
|
||||
RET
|
||||
|
||||
/* return fault address */
|
||||
TEXT getfar(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpFAR), C(0x0)
|
||||
RET
|
||||
|
||||
/* set the translation table base */
|
||||
TEXT putttb(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpTTB), C(0x0)
|
||||
RET
|
||||
|
||||
/*
|
||||
* enable mmu, i and d caches
|
||||
*/
|
||||
TEXT mmuenable(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
ORR $(CpCmmuena|CpCdcache|CpCicache|CpCwb|CpCsystem), R0
|
||||
BIC $(CpCrom), R0
|
||||
MCR CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
RET
|
||||
|
||||
TEXT mmudisable(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
BIC $(CpCmmuena|CpCdcache|CpCicache|CpCwb|CpCvivec), R0
|
||||
MCR CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
RET
|
||||
|
||||
/*
|
||||
* use exception vectors at 0xffff0000
|
||||
*/
|
||||
TEXT mappedIvecEnable(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
ORR $(CpCvivec), R0
|
||||
MCR CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
RET
|
||||
TEXT mappedIvecDisable(SB), $-4
|
||||
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
BIC $(CpCvivec), R0
|
||||
MCR CpMMU, 0, R0, C(CpControl), C(0x0)
|
||||
RET
|
||||
|
||||
/* set the translation table base */
|
||||
TEXT putdac(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpDAC), C(0x0)
|
||||
RET
|
||||
|
||||
/* set address translation pid */
|
||||
TEXT putpid(SB), $-4
|
||||
MCR CpMMU, 0, R0, C(CpPID), C(0x0)
|
||||
RET
|
||||
|
||||
/*
|
||||
* set the stack value for the mode passed in R0
|
||||
*/
|
||||
TEXT setr13(SB), $-4
|
||||
MOVW 4(FP), R1
|
||||
|
||||
MOVW CPSR, R2
|
||||
BIC $PsrMask, R2, R3
|
||||
ORR R0, R3
|
||||
MOVW R3, CPSR
|
||||
|
||||
MOVW R13, R0
|
||||
MOVW R1, R13
|
||||
|
||||
MOVW R2, CPSR
|
||||
RET
|
||||
|
||||
/*
|
||||
* exception vectors, copied by trapinit() to somewhere useful
|
||||
*/
|
||||
|
||||
TEXT vectors(SB), $-4
|
||||
MOVW 0x18(R15), R15 /* reset */
|
||||
MOVW 0x18(R15), R15 /* undefined */
|
||||
MOVW 0x18(R15), R15 /* SWI */
|
||||
MOVW 0x18(R15), R15 /* prefetch abort */
|
||||
MOVW 0x18(R15), R15 /* data abort */
|
||||
MOVW 0x18(R15), R15 /* reserved */
|
||||
MOVW 0x18(R15), R15 /* IRQ */
|
||||
MOVW 0x18(R15), R15 /* FIQ */
|
||||
|
||||
TEXT vtable(SB), $-4
|
||||
WORD $_vsvc(SB) /* reset, in svc mode already */
|
||||
WORD $_vund(SB) /* undefined, switch to svc mode */
|
||||
WORD $_vsvc(SB) /* swi, in svc mode already */
|
||||
WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */
|
||||
WORD $_vdabt(SB) /* data abort, switch to svc mode */
|
||||
WORD $_vsvc(SB) /* reserved */
|
||||
WORD $_virq(SB) /* IRQ, switch to svc mode */
|
||||
WORD $_vfiq(SB) /* FIQ, switch to svc mode */
|
||||
|
||||
TEXT _vrst(SB), $-4
|
||||
BL resettrap(SB)
|
||||
|
||||
TEXT _vsvc(SB), $-4 /* SWI */
|
||||
MOVW.W R14, -4(R13) /* ureg->pc = interupted PC */
|
||||
MOVW SPSR, R14 /* ureg->psr = SPSR */
|
||||
MOVW.W R14, -4(R13) /* ... */
|
||||
MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */
|
||||
MOVW.W R14, -4(R13) /* ... */
|
||||
MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */
|
||||
MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
|
||||
MOVW R13, R0 /* first arg is pointer to ureg */
|
||||
SUB $8, R13 /* space for argument+link */
|
||||
|
||||
BL syscall(SB)
|
||||
|
||||
ADD $(8+4*15), R13 /* make r13 point to ureg->type */
|
||||
MOVW 8(R13), R14 /* restore link */
|
||||
MOVW 4(R13), R0 /* restore SPSR */
|
||||
MOVW R0, SPSR /* ... */
|
||||
MOVM.DB.S (R13), [R0-R14] /* restore registers */
|
||||
ADD $8, R13 /* pop past ureg->{type+psr} */
|
||||
RFE /* MOVM.IA.S.W (R13), [R15] */
|
||||
|
||||
TEXT _vund(SB), $-4 /* undefined */
|
||||
MOVM.IA [R0-R4], (R13) /* free some working space */
|
||||
MOVW $PsrMund, R0
|
||||
B _vswitch
|
||||
|
||||
TEXT _vpabt(SB), $-4 /* prefetch abort */
|
||||
MOVM.IA [R0-R4], (R13) /* free some working space */
|
||||
MOVW $PsrMabt, R0 /* r0 = type */
|
||||
B _vswitch
|
||||
|
||||
TEXT _vdabt(SB), $-4 /* prefetch abort */
|
||||
MOVM.IA [R0-R4], (R13) /* free some working space */
|
||||
MOVW $(PsrMabt+1), R0 /* r0 = type */
|
||||
B _vswitch
|
||||
|
||||
TEXT _virq(SB), $-4 /* IRQ */
|
||||
MOVM.IA [R0-R4], (R13) /* free some working space */
|
||||
MOVW $PsrMirq, R0 /* r0 = type */
|
||||
B _vswitch
|
||||
|
||||
/*
|
||||
* come here with type in R0 and R13 pointing above saved [r0-r4]
|
||||
* and type in r0. we'll switch to SVC mode and then call trap.
|
||||
*/
|
||||
_vswitch:
|
||||
MOVW SPSR, R1 /* save SPSR for ureg */
|
||||
MOVW R14, R2 /* save interrupted pc for ureg */
|
||||
MOVW R13, R3 /* save pointer to where the original [R0-R3] are */
|
||||
|
||||
/* switch to svc mode */
|
||||
MOVW CPSR, R14
|
||||
BIC $PsrMask, R14
|
||||
ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14
|
||||
MOVW R14, CPSR
|
||||
|
||||
/* interupted code kernel or user? */
|
||||
AND.S $0xf, R1, R4
|
||||
BEQ _userexcep
|
||||
|
||||
/* here for trap from SVC mode */
|
||||
MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */
|
||||
MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */
|
||||
MOVM.DB.W [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */
|
||||
MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
|
||||
MOVW R13, R0 /* first arg is pointer to ureg */
|
||||
SUB $8, R13 /* space for argument+link (for debugger) */
|
||||
MOVW $0xdeaddead,R11 /* marker */
|
||||
|
||||
BL trap(SB)
|
||||
|
||||
ADD $(8+4*15), R13 /* make r13 point to ureg->type */
|
||||
MOVW 8(R13), R14 /* restore link */
|
||||
MOVW 4(R13), R0 /* restore SPSR */
|
||||
MOVW R0, SPSR /* ... */
|
||||
MOVM.DB (R13), [R0-R14] /* restore registers */
|
||||
ADD $8, R13 /* pop past ureg->{type+psr} */
|
||||
RFE /* MOVM.IA.S.W (R13), [R15] */
|
||||
|
||||
/* here for trap from USER mode */
|
||||
_userexcep:
|
||||
MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */
|
||||
MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */
|
||||
MOVM.DB.W.S [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */
|
||||
MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
|
||||
MOVW R13, R0 /* first arg is pointer to ureg */
|
||||
SUB $8, R13 /* space for argument+link (for debugger) */
|
||||
|
||||
BL trap(SB)
|
||||
|
||||
ADD $(8+4*15), R13 /* make r13 point to ureg->type */
|
||||
MOVW 8(R13), R14 /* restore link */
|
||||
MOVW 4(R13), R0 /* restore SPSR */
|
||||
MOVW R0, SPSR /* ... */
|
||||
MOVM.DB.S (R13), [R0-R14] /* restore registers */
|
||||
ADD $8, R13 /* pop past ureg->{type+psr} */
|
||||
RFE /* MOVM.IA.S.W (R13), [R15] */
|
||||
|
||||
TEXT _vfiq(SB), $-4 /* FIQ */
|
||||
RFE /* FIQ is special, ignore it for now */
|
||||
|
||||
/*
|
||||
* This is the first jump from kernel to user mode.
|
||||
* Fake a return from interrupt.
|
||||
*
|
||||
* Enter with R0 containing the user stack pointer.
|
||||
* UTZERO + 0x20 is always the entry point.
|
||||
*
|
||||
*/
|
||||
TEXT touser(SB),$-4
|
||||
/* store the user stack pointer into the USR_r13 */
|
||||
MOVM.DB.W [R0], (R13)
|
||||
MOVM.S.IA.W (R13),[R13]
|
||||
|
||||
/* set up a PSR for user level */
|
||||
MOVW $(PsrMusr), R0
|
||||
MOVW R0,SPSR
|
||||
|
||||
/* save the PC on the stack */
|
||||
MOVW $(UTZERO+0x20), R0
|
||||
MOVM.DB.W [R0],(R13)
|
||||
|
||||
/* return from interrupt */
|
||||
RFE /* MOVM.IA.S.W (R13), [R15] */
|
||||
|
||||
/*
|
||||
* here to jump to a newly forked process
|
||||
*/
|
||||
TEXT forkret(SB),$-4
|
||||
ADD $(4*15), R13 /* make r13 point to ureg->type */
|
||||
MOVW 8(R13), R14 /* restore link */
|
||||
MOVW 4(R13), R0 /* restore SPSR */
|
||||
MOVW R0, SPSR /* ... */
|
||||
MOVM.DB.S (R13), [R0-R14] /* restore registers */
|
||||
ADD $8, R13 /* pop past ureg->{type+psr} */
|
||||
RFE /* MOVM.IA.S.W (R13), [R15] */
|
||||
|
||||
TEXT splhi(SB), $-4
|
||||
/* save caller pc in Mach */
|
||||
MOVW $(MACHADDR+0x04),R2
|
||||
MOVW R14,0(R2)
|
||||
/* turn off interrupts */
|
||||
MOVW CPSR, R0
|
||||
ORR $(PsrDirq), R0, R1
|
||||
MOVW R1, CPSR
|
||||
RET
|
||||
|
||||
TEXT spllo(SB), $-4
|
||||
MOVW CPSR, R0
|
||||
BIC $(PsrDirq), R0, R1
|
||||
MOVW R1, CPSR
|
||||
RET
|
||||
|
||||
TEXT splx(SB), $-4
|
||||
/* save caller pc in Mach */
|
||||
MOVW $(MACHADDR+0x04),R2
|
||||
MOVW R14,0(R2)
|
||||
/* reset interrupt level */
|
||||
MOVW R0, R1
|
||||
MOVW CPSR, R0
|
||||
MOVW R1, CPSR
|
||||
RET
|
||||
|
||||
TEXT splxpc(SB), $-4 /* for iunlock */
|
||||
MOVW R0, R1
|
||||
MOVW CPSR, R0
|
||||
MOVW R1, CPSR
|
||||
RET
|
||||
|
||||
TEXT spldone(SB), $0
|
||||
RET
|
||||
|
||||
TEXT islo(SB), $-4
|
||||
MOVW CPSR, R0
|
||||
AND $(PsrDirq), R0
|
||||
EOR $(PsrDirq), R0
|
||||
RET
|
||||
|
||||
TEXT cpsrr(SB), $-4
|
||||
MOVW CPSR, R0
|
||||
RET
|
||||
|
||||
TEXT spsrr(SB), $-4
|
||||
MOVW SPSR, R0
|
||||
RET
|
||||
|
||||
TEXT getsp(SB), $-4
|
||||
MOVW R13, R0
|
||||
RET
|
||||
|
||||
TEXT getlink(SB), $-4
|
||||
MOVW R14, R0
|
||||
RET
|
||||
|
||||
TEXT getcallerpc(SB), $-4
|
||||
MOVW 0(R13), R0
|
||||
RET
|
||||
|
||||
TEXT tas(SB), $-4
|
||||
TEXT _tas(SB), $-4
|
||||
MOVW R0, R1
|
||||
MOVW $0xDEADDEAD, R0
|
||||
MOVW R0, R3
|
||||
SWPW R0, (R1)
|
||||
CMP.S R0, R3
|
||||
BEQ _tasout
|
||||
EOR R3, R3
|
||||
CMP.S R0, R3
|
||||
BEQ _tasout
|
||||
MOVW $1,R15
|
||||
_tasout:
|
||||
RET
|
||||
|
||||
TEXT setlabel(SB), $-4
|
||||
MOVW R13, 0(R0) /* sp */
|
||||
MOVW R14, 4(R0) /* pc */
|
||||
MOVW $0, R0
|
||||
RET
|
||||
|
||||
TEXT gotolabel(SB), $-4
|
||||
MOVW 0(R0), R13 /* sp */
|
||||
MOVW 4(R0), R14 /* pc */
|
||||
MOVW $1, R0
|
||||
RET
|
||||
|
||||
/* save the state machine in power_state[] for an upcoming suspend
|
||||
*/
|
||||
TEXT setpowerlabel(SB), $-4
|
||||
MOVW $power_state+0(SB), R0
|
||||
/* svc */ /* power_state[]: what */
|
||||
MOVW R1, 0(R0)
|
||||
MOVW R2, 4(R0)
|
||||
MOVW R3, 8(R0)
|
||||
MOVW R4, 12(R0)
|
||||
MOVW R5, 16(R0)
|
||||
MOVW R6, 20(R0)
|
||||
MOVW R7, 24(R0)
|
||||
MOVW R8, 28(R0)
|
||||
MOVW R9, 32(R0)
|
||||
MOVW R10,36(R0)
|
||||
MOVW R11,40(R0)
|
||||
MOVW R12,44(R0)
|
||||
MOVW R13,48(R0)
|
||||
MOVW R14,52(R0)
|
||||
MOVW SPSR, R1
|
||||
MOVW R1, 56(R0)
|
||||
MOVW CPSR, R2
|
||||
MOVW R2, 60(R0)
|
||||
/* copro */
|
||||
MRC CpMMU, 0, R3, C(CpDAC), C(0x0)
|
||||
MOVW R3, 144(R0)
|
||||
MRC CpMMU, 0, R3, C(CpTTB), C(0x0)
|
||||
MOVW R3, 148(R0)
|
||||
MRC CpMMU, 0, R3, C(CpControl), C(0x0)
|
||||
MOVW R3, 152(R0)
|
||||
MRC CpMMU, 0, R3, C(CpFSR), C(0x0)
|
||||
MOVW R3, 156(R0)
|
||||
MRC CpMMU, 0, R3, C(CpFAR), C(0x0)
|
||||
MOVW R3, 160(R0)
|
||||
MRC CpMMU, 0, R3, C(CpPID), C(0x0)
|
||||
MOVW R3, 164(R0)
|
||||
/* usr */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xdf), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW SPSR, R11
|
||||
MOVW R11, 168(R0)
|
||||
MOVW R12, 172(R0)
|
||||
MOVW R13, 176(R0)
|
||||
MOVW R14, 180(R0)
|
||||
/* irq */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xd2), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW SPSR, R11
|
||||
MOVW R11, 64(R0)
|
||||
MOVW R12, 68(R0)
|
||||
MOVW R13, 72(R0)
|
||||
MOVW R14, 76(R0)
|
||||
/* und */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xdb), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW SPSR, R11
|
||||
MOVW R11, 80(R0)
|
||||
MOVW R12, 84(R0)
|
||||
MOVW R13, 88(R0)
|
||||
MOVW R14, 92(R0)
|
||||
/* abt */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xd7), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW SPSR, R11
|
||||
MOVW R11, 96(R0)
|
||||
MOVW R12, 100(R0)
|
||||
MOVW R13, 104(R0)
|
||||
MOVW R14, 108(R0)
|
||||
/* fiq */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xd1), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW SPSR, R7
|
||||
MOVW R7, 112(R0)
|
||||
MOVW R8, 116(R0)
|
||||
MOVW R9, 120(R0)
|
||||
MOVW R10,124(R0)
|
||||
MOVW R11,128(R0)
|
||||
MOVW R12,132(R0)
|
||||
MOVW R13,136(R0)
|
||||
MOVW R14,140(R0)
|
||||
/* done */
|
||||
MOVW R2, CPSR
|
||||
MOVW R1, SPSR
|
||||
MOVW $0, R0
|
||||
RET
|
||||
|
||||
/* Entered after a resume from suspend state.
|
||||
* The bootldr jumps here after a processor reset.
|
||||
*/
|
||||
TEXT power_resume(SB), $-4
|
||||
MOVW $setR12(SB), R12 /* load the SB */
|
||||
/* SVC mode, interrupts disabled */
|
||||
MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
|
||||
MOVW R1, CPSR
|
||||
/* gotopowerlabel() */
|
||||
/* svc */
|
||||
|
||||
MOVW $power_state+0(SB), R0
|
||||
MOVW 56(R0), R1 /* R1: SPSR, R2: CPSR */
|
||||
MOVW 60(R0), R2
|
||||
MOVW R1, SPSR
|
||||
MOVW R2, CPSR
|
||||
/* copro */
|
||||
/* flush caches */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
|
||||
/* drain prefetch */
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
/* drain write buffer */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
|
||||
MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x7)
|
||||
MOVW 144(R0), R3
|
||||
MCR CpMMU, 0, R3, C(CpDAC), C(0x0)
|
||||
MOVW 148(R0), R3
|
||||
MCR CpMMU, 0, R3, C(CpTTB), C(0x0)
|
||||
MOVW 156(R0), R3
|
||||
MCR CpMMU, 0, R3, C(CpFSR), C(0x0)
|
||||
MOVW 160(R0), R3
|
||||
MCR CpMMU, 0, R3, C(CpFAR), C(0x0)
|
||||
MOVW 164(R0), R3
|
||||
MCR CpMMU, 0, R3, C(CpPID), C(0x0)
|
||||
MOVW 152(R0), R3
|
||||
MCR CpMMU, 0, R3, C(CpControl), C(0x0) /* Enable cache */
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
/* flush i&d caches */
|
||||
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
|
||||
/* flush tlb */
|
||||
MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x7), 0
|
||||
/* drain prefetch */
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
/* usr */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xdf), R3
|
||||
MOVW 168(R0), R11
|
||||
MOVW 172(R0), R12
|
||||
MOVW 176(R0), R13
|
||||
MOVW 180(R0), R14
|
||||
MOVW R11, SPSR
|
||||
/* irq */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xd2), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW 64(R0), R11
|
||||
MOVW 68(R0), R12
|
||||
MOVW 72(R0), R13
|
||||
MOVW 76(R0), R14
|
||||
MOVW R11, SPSR
|
||||
/* und */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xdb), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW 80(R0), R11
|
||||
MOVW 84(R0), R12
|
||||
MOVW 88(R0), R13
|
||||
MOVW 92(R0), R14
|
||||
MOVW R11, SPSR
|
||||
/* abt */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xd7), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW 96(R0), R11
|
||||
MOVW 100(R0), R12
|
||||
MOVW 104(R0), R13
|
||||
MOVW 108(R0), R14
|
||||
MOVW R11, SPSR
|
||||
/* fiq */
|
||||
BIC $(PsrMask), R2, R3
|
||||
ORR $(0xd1), R3
|
||||
MOVW R3, CPSR
|
||||
MOVW 112(R0), R7
|
||||
MOVW 116(R0), R8
|
||||
MOVW 120(R0), R9
|
||||
MOVW 124(R0), R10
|
||||
MOVW 128(R0), R11
|
||||
MOVW 132(R0), R12
|
||||
MOVW 136(R0), R13
|
||||
MOVW 140(R0), R14
|
||||
MOVW R7, SPSR
|
||||
/* svc */
|
||||
MOVW 56(R0), R1
|
||||
MOVW 60(R0), R2
|
||||
MOVW R1, SPSR
|
||||
MOVW R2, CPSR
|
||||
MOVW 0(R0), R1
|
||||
MOVW 4(R0), R2
|
||||
MOVW 8(R0), R3
|
||||
MOVW 12(R0),R4
|
||||
MOVW 16(R0),R5
|
||||
MOVW 20(R0),R6
|
||||
MOVW 24(R0),R7
|
||||
MOVW 28(R0),R8
|
||||
MOVW 32(R0),R9
|
||||
MOVW 36(R0),R10
|
||||
MOVW 40(R0),R11
|
||||
MOVW 44(R0),R12
|
||||
MOVW 48(R0),R13
|
||||
MOVW 52(R0),R14
|
||||
RET
|
||||
loop:
|
||||
B loop
|
||||
|
||||
TEXT power_down(SB), $-4
|
||||
|
||||
TEXT sa1100_power_off<>+0(SB),$8
|
||||
MOVW resetregs+0(SB),R7
|
||||
MOVW gpioregs+0(SB),R6
|
||||
MOVW memconfregs+0(SB),R5
|
||||
MOVW powerregs+0(SB),R3
|
||||
|
||||
|
||||
/* wakeup on power | rtc */
|
||||
MOVW $(PWR_rtc|PWR_gpio0),R2
|
||||
MOVW R2,0xc(R3)
|
||||
|
||||
/* clear reset status */
|
||||
MOVW $(RCSR_all), R2
|
||||
MOVW R2, 0x4(R7)
|
||||
/* float */
|
||||
MOVW $(PCFR_opde|PCFR_fp|PCFR_fs), R2
|
||||
MOVW R2,0x10(R3)
|
||||
/* sleep state */
|
||||
MOVW $0,R2
|
||||
MOVW R2,0x18(R3)
|
||||
/* set resume address (pspr)*/
|
||||
MOVW $resumeaddr+0(SB),R1
|
||||
MOVW 0x0(R1), R2
|
||||
MOVW R2,0x8(R3)
|
||||
|
||||
BL cacheflush(SB)
|
||||
|
||||
/* disable clock switching */
|
||||
MCR CpPWR, 0, R1, C(CpTest), C(0x2), 2
|
||||
|
||||
/* adjust mem timing */
|
||||
MOVW memconfregs+0(SB),R5
|
||||
MOVW 0x1c(R5), R2
|
||||
ORR $(MDREFR_k1db2), R2
|
||||
MOVW R2, 0x1c(R5)
|
||||
|
||||
/* set PLL to lower speed w/ delay (ppcr = 0)*/
|
||||
MOVW powerregs+0(SB),R3
|
||||
MOVW $(120*206),R0
|
||||
l11: SUB $1,R0
|
||||
BGT l11
|
||||
MOVW $0, R2
|
||||
MOVW R2, 0x14(R3)
|
||||
MOVW $(120*206),R0
|
||||
l12: SUB $1,R0
|
||||
BGT l12
|
||||
|
||||
/* setup registers for suspend procedure:
|
||||
* 1. clear RT in mscx (R1, R7, R8)
|
||||
* 2. clear DRI in mdrefr (R4)
|
||||
* 3. set slfrsh in mdrefr (R6)
|
||||
* 4. clear DE in mdcnfg (R9)
|
||||
* 5. clear dram refresh (R10)
|
||||
* 6. force sleep (R2)
|
||||
*/
|
||||
/* 1 */
|
||||
MOVW 0x10(R5), R2
|
||||
BIC $(MSC_rt), R2
|
||||
MOVW R2, R1
|
||||
MOVW 0x14(R5), R2
|
||||
BIC $(MSC_rt), R2
|
||||
MOVW R2, R7
|
||||
MOVW 0x2c(R5), R2
|
||||
BIC $(MSC_rt), R2
|
||||
MOVW R2, R8
|
||||
/* 2 */
|
||||
MOVW 0x1c(R5), R2
|
||||
BIC $(0xff00), R2
|
||||
BIC $(0x00f0), R2
|
||||
MOVW R2, R4
|
||||
/* 3 */
|
||||
ORR $(MDREFR_slfrsh), R2, R6
|
||||
/* 4 */
|
||||
MOVW 0x0(R5), R9
|
||||
BIC $(MDCFNG_de), R9, R9
|
||||
/* 5 */
|
||||
MOVW R4, R2
|
||||
BIC $(MDREFR_slfrsh), R2, R2
|
||||
BIC $(MDREFR_e1pin), R2, R2
|
||||
MOVW R2, R10
|
||||
/* 6 */
|
||||
MOVW $1,R2
|
||||
|
||||
TEXT power_magic(SB), $-4
|
||||
/* power_code gets copied into the area of no-ops below,
|
||||
* at a cache-line boundary (8 instructions)
|
||||
*/
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
MOVW R0, R0
|
||||
|
||||
TEXT power_code(SB), $-4
|
||||
/* Follow the procedure; this code gets copied to the no-op
|
||||
* area preceding this code
|
||||
*/
|
||||
/* 1 */
|
||||
MOVW R1, 0x10(R5)
|
||||
MOVW R7, 0x14(R5)
|
||||
MOVW R8, 0x2c(R5)
|
||||
/* 2 */
|
||||
MOVW R4, 0x1c(R5)
|
||||
/* 3 */
|
||||
MOVW R6, 0x1c(R5)
|
||||
/* 4 */
|
||||
MOVW R9, 0x0(R5)
|
||||
/* 5 */
|
||||
MOVW R10, 0x1c(R5)
|
||||
/* 6 */
|
||||
MOVW R2, 0x0(R3)
|
||||
slloop:
|
||||
B slloop /* loop waiting for sleep */
|
||||
|
||||
/* The first MCR instruction of this function needs to be on a cache-line
|
||||
* boundary; to make this happen, it will be copied to the first cache-line
|
||||
* boundary 8 words from the start of doze.
|
||||
*
|
||||
* Doze puts the machine into idle mode. Any interrupt will get it out
|
||||
* at the next instruction (the RET, to be precise).
|
||||
*/
|
||||
TEXT doze(SB), $-4
|
||||
MOVW $UCDRAMZERO, R1
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
MOVW R0,R0
|
||||
RET
|
||||
|
||||
TEXT doze_code(SB), $-4
|
||||
MCR CpPWR, 0, R0, C(CpTest), C(0x2), 2
|
||||
MOVW (R1), R0
|
||||
MCR CpPWR, 0, R0, C(CpTest), C(0x8), 2
|
|
@ -1,536 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "init.h"
|
||||
#include "pool.h"
|
||||
|
||||
Mach *m;
|
||||
Proc *up;
|
||||
Conf conf;
|
||||
int noprint;
|
||||
|
||||
void
|
||||
main(void)
|
||||
{
|
||||
mmuinvalidate();
|
||||
|
||||
/* zero out bss */
|
||||
memset(edata, 0, end-edata);
|
||||
|
||||
/* point to Mach structure */
|
||||
m = (Mach*)MACHADDR;
|
||||
memset(m, 0, sizeof(Mach));
|
||||
m->ticks = 1;
|
||||
|
||||
active.machs[0] = 1;
|
||||
|
||||
rs232power(1);
|
||||
quotefmtinstall();
|
||||
iprint("\nPlan 9 bitsy kernel\n");
|
||||
confinit();
|
||||
xinit();
|
||||
mmuinit();
|
||||
machinit();
|
||||
trapinit();
|
||||
sa1110_uartsetup(1);
|
||||
dmainit();
|
||||
screeninit();
|
||||
printinit(); /* from here on, print works, before this we need iprint */
|
||||
clockinit();
|
||||
procinit0();
|
||||
initseg();
|
||||
links();
|
||||
chandevreset();
|
||||
pageinit();
|
||||
swapinit();
|
||||
userinit();
|
||||
powerinit();
|
||||
schedinit();
|
||||
}
|
||||
|
||||
/* need to do better */
|
||||
void
|
||||
reboot(void*, void*, ulong)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* exit kernel either on a panic or user request
|
||||
*/
|
||||
void
|
||||
exit(int)
|
||||
{
|
||||
void (*f)(void);
|
||||
|
||||
cpushutdown();
|
||||
splhi();
|
||||
iprint("it's a wonderful day to die\n");
|
||||
cacheflush();
|
||||
mmuinvalidate();
|
||||
mmudisable();
|
||||
f = nil;
|
||||
(*f)();
|
||||
}
|
||||
|
||||
static uchar *sp;
|
||||
|
||||
/*
|
||||
* starting place for first process
|
||||
*/
|
||||
void
|
||||
init0(void)
|
||||
{
|
||||
up->nerrlab = 0;
|
||||
|
||||
spllo();
|
||||
|
||||
/*
|
||||
* These are o.k. because rootinit is null.
|
||||
* Then early kproc's will have a root and dot.
|
||||
*/
|
||||
up->slash = namec("#/", Atodir, 0, 0);
|
||||
pathclose(up->slash->path);
|
||||
up->slash->path = newpath("/");
|
||||
up->dot = cclone(up->slash);
|
||||
|
||||
chandevinit();
|
||||
|
||||
if(!waserror()){
|
||||
ksetenv("terminal", "bitsy", 0);
|
||||
ksetenv("cputype", "arm", 0);
|
||||
if(cpuserver)
|
||||
ksetenv("service", "cpu", 0);
|
||||
else
|
||||
ksetenv("service", "terminal", 0);
|
||||
poperror();
|
||||
}
|
||||
kproc("alarm", alarmkproc, 0);
|
||||
kproc("power", powerkproc, 0);
|
||||
|
||||
touser(sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* pass boot arguments to /boot
|
||||
*/
|
||||
static uchar *
|
||||
pusharg(char *p)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = strlen(p)+1;
|
||||
sp -= n;
|
||||
memmove(sp, p, n);
|
||||
return sp;
|
||||
}
|
||||
static void
|
||||
bootargs(ulong base)
|
||||
{
|
||||
int i, ac;
|
||||
uchar *av[32];
|
||||
uchar *bootpath;
|
||||
uchar **lsp;
|
||||
|
||||
/*
|
||||
* the sizeof(Sargs) is to make the validaddr check in
|
||||
* trap.c's syscall() work even when we have less than the
|
||||
* max number of args.
|
||||
*/
|
||||
sp = (uchar*)base + BY2PG - sizeof(Sargs);
|
||||
|
||||
bootpath = pusharg("/boot/boot");
|
||||
ac = 0;
|
||||
av[ac++] = pusharg("boot");
|
||||
|
||||
/* 4 byte word align stack */
|
||||
sp = (uchar*)((ulong)sp & ~3);
|
||||
|
||||
/* build argc, argv on stack */
|
||||
sp -= (ac+1)*sizeof(sp);
|
||||
lsp = (uchar**)sp;
|
||||
for(i = 0; i < ac; i++)
|
||||
*lsp++ = av[i] + ((USTKTOP - BY2PG) - base);
|
||||
*lsp = 0;
|
||||
|
||||
/* push argv onto stack */
|
||||
sp -= BY2WD;
|
||||
lsp = (uchar**)sp;
|
||||
*lsp = sp + BY2WD + ((USTKTOP - BY2PG) - base);
|
||||
|
||||
/* push pointer to "/boot" */
|
||||
sp -= BY2WD;
|
||||
lsp = (uchar**)sp;
|
||||
*lsp = bootpath + ((USTKTOP - BY2PG) - base);
|
||||
|
||||
/* leave space for where the initcode's caller's return PC would normally reside */
|
||||
sp -= BY2WD;
|
||||
|
||||
/* relocate stack to user's virtual addresses */
|
||||
sp += (USTKTOP - BY2PG) - base;
|
||||
}
|
||||
|
||||
/*
|
||||
* create the first process
|
||||
*/
|
||||
void
|
||||
userinit(void)
|
||||
{
|
||||
Proc *p;
|
||||
Segment *s;
|
||||
KMap *k;
|
||||
Page *pg;
|
||||
|
||||
/* no processes yet */
|
||||
up = nil;
|
||||
|
||||
p = newproc();
|
||||
p->pgrp = newpgrp();
|
||||
p->egrp = smalloc(sizeof(Egrp));
|
||||
p->egrp->ref = 1;
|
||||
p->fgrp = dupfgrp(nil);
|
||||
p->rgrp = newrgrp();
|
||||
p->procmode = 0640;
|
||||
|
||||
kstrdup(&eve, "");
|
||||
kstrdup(&p->text, "*init*");
|
||||
kstrdup(&p->user, eve);
|
||||
|
||||
/*
|
||||
* Kernel Stack
|
||||
*/
|
||||
p->sched.pc = (ulong)init0;
|
||||
p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
|
||||
|
||||
/*
|
||||
* User Stack
|
||||
*/
|
||||
s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
|
||||
p->seg[SSEG] = s;
|
||||
pg = newpage(1, 0, USTKTOP-BY2PG);
|
||||
segpage(s, pg);
|
||||
k = kmap(pg);
|
||||
bootargs(VA(k));
|
||||
kunmap(k);
|
||||
|
||||
/*
|
||||
* Text
|
||||
*/
|
||||
s = newseg(SG_TEXT, UTZERO, 1);
|
||||
p->seg[TSEG] = s;
|
||||
pg = newpage(1, 0, UTZERO);
|
||||
pg->txtflush = ~0;
|
||||
segpage(s, pg);
|
||||
k = kmap(s->map[0]->pages[0]);
|
||||
memmove((ulong*)VA(k), initcode, sizeof initcode);
|
||||
kunmap(k);
|
||||
|
||||
ready(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* set mach dependent process state for a new process
|
||||
*/
|
||||
void
|
||||
procsetup(Proc *p)
|
||||
{
|
||||
p->fpstate = FPinit;
|
||||
}
|
||||
|
||||
void
|
||||
procfork(Proc*)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the mach dependent part of the process state.
|
||||
*/
|
||||
void
|
||||
procsave(Proc *p)
|
||||
{
|
||||
USED(p);
|
||||
}
|
||||
|
||||
/* place holder */
|
||||
/*
|
||||
* dummy since rdb is not included
|
||||
*/
|
||||
void
|
||||
rdb(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* probe the last location in a meg of memory, make sure it's not
|
||||
* reflected into something else we've already found.
|
||||
*/
|
||||
int
|
||||
probemem(ulong addr)
|
||||
{
|
||||
int i;
|
||||
ulong *p;
|
||||
ulong a;
|
||||
|
||||
addr += OneMeg - sizeof(ulong);
|
||||
p = (ulong*)addr;
|
||||
*p = addr;
|
||||
for(i=0; i<nelem(conf.mem); i++){
|
||||
for(a = conf.mem[i].base+OneMeg-sizeof(ulong); a < conf.mem[i].limit; a += OneMeg){
|
||||
p = (ulong*)a;
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
p = (ulong*)addr;
|
||||
if(*p != addr)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* we assume that the kernel is at the beginning of one of the
|
||||
* contiguous chunks of memory.
|
||||
*/
|
||||
void
|
||||
confinit(void)
|
||||
{
|
||||
int i, j;
|
||||
ulong addr;
|
||||
ulong ktop;
|
||||
|
||||
/* find first two contiguous sections of available memory */
|
||||
addr = PHYSDRAM0;
|
||||
for(i=0; i<nelem(conf.mem); i++){
|
||||
conf.mem[i].base = addr;
|
||||
conf.mem[i].limit = addr;
|
||||
}
|
||||
for(j=0; j<nelem(conf.mem); j++){
|
||||
conf.mem[j].base = addr;
|
||||
conf.mem[j].limit = addr;
|
||||
|
||||
for(i = 0; i < 512; i++){
|
||||
if(probemem(addr) == 0)
|
||||
break;
|
||||
addr += OneMeg;
|
||||
}
|
||||
for(; i < 512; i++){
|
||||
if(probemem(addr) < 0)
|
||||
break;
|
||||
addr += OneMeg;
|
||||
conf.mem[j].limit = addr;
|
||||
}
|
||||
}
|
||||
|
||||
conf.npage = 0;
|
||||
for(i=0; i<nelem(conf.mem); i++){
|
||||
/* take kernel out of allocatable space */
|
||||
ktop = PGROUND((ulong)end);
|
||||
if(ktop >= conf.mem[i].base && ktop <= conf.mem[i].limit)
|
||||
conf.mem[i].base = ktop;
|
||||
|
||||
/* zero memory */
|
||||
memset((void*)conf.mem[i].base, 0, conf.mem[i].limit - conf.mem[i].base);
|
||||
|
||||
conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
|
||||
conf.npage += conf.mem[i].npage;
|
||||
}
|
||||
|
||||
if(conf.npage > 16*MB/BY2PG){
|
||||
conf.upages = (conf.npage*60)/100;
|
||||
imagmem->minarena = 4*1024*1024;
|
||||
}else
|
||||
conf.upages = (conf.npage*40)/100;
|
||||
conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
|
||||
|
||||
/* only one processor */
|
||||
conf.nmach = 1;
|
||||
|
||||
/* set up other configuration parameters */
|
||||
conf.nproc = 100;
|
||||
conf.nswap = conf.npage*3;
|
||||
conf.nswppo = 4096;
|
||||
conf.nimage = 200;
|
||||
|
||||
conf.monitor = 1;
|
||||
|
||||
conf.copymode = 0; /* copy on write */
|
||||
}
|
||||
|
||||
GPIOregs *gpioregs;
|
||||
ulong *egpioreg = (ulong*)EGPIOREGS;
|
||||
PPCregs *ppcregs;
|
||||
MemConfRegs *memconfregs;
|
||||
PowerRegs *powerregs;
|
||||
ResetRegs *resetregs;
|
||||
|
||||
/*
|
||||
* configure the machine
|
||||
*/
|
||||
void
|
||||
machinit(void)
|
||||
{
|
||||
/* set direction of SA1110 io pins and select alternate functions for some */
|
||||
gpioregs = mapspecial(GPIOREGS, sizeof(GPIOregs));
|
||||
gpioregs->direction =
|
||||
GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
|
||||
|GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o
|
||||
|GPIO_CLK_SET0_o|GPIO_CLK_SET1_o
|
||||
|GPIO_L3_SDA_io|GPIO_L3_MODE_o|GPIO_L3_SCLK_o
|
||||
|GPIO_COM_RTS_o;
|
||||
gpioregs->rising = 0;
|
||||
gpioregs->falling = 0;
|
||||
gpioregs->altfunc |=
|
||||
GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
|
||||
|GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o
|
||||
|GPIO_SSP_CLK_i;
|
||||
|
||||
/* map in special H3650 io pins */
|
||||
egpioreg = mapspecial(EGPIOREGS, sizeof(ulong));
|
||||
|
||||
/* map in peripheral pin controller (ssp will need it) */
|
||||
ppcregs = mapspecial(PPCREGS, sizeof(PPCregs));
|
||||
|
||||
/* SA1110 power management */
|
||||
powerregs = mapspecial(POWERREGS, sizeof(PowerRegs));
|
||||
|
||||
/* memory configuraton */
|
||||
memconfregs = mapspecial(MEMCONFREGS, sizeof(MemConfRegs));
|
||||
|
||||
/* reset controller */
|
||||
resetregs = mapspecial(RESETREGS, sizeof(ResetRegs));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* manage egpio bits
|
||||
*/
|
||||
static ulong egpiosticky;
|
||||
|
||||
void
|
||||
egpiobits(ulong bits, int on)
|
||||
{
|
||||
if(on)
|
||||
egpiosticky |= bits;
|
||||
else
|
||||
egpiosticky &= ~bits;
|
||||
*egpioreg = egpiosticky;
|
||||
}
|
||||
|
||||
void
|
||||
rs232power(int on)
|
||||
{
|
||||
egpiobits(EGPIO_rs232_power, on);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void
|
||||
audioamppower(int on)
|
||||
{
|
||||
egpiobits(EGPIO_audio_power, on);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void
|
||||
audioicpower(int on)
|
||||
{
|
||||
egpiobits(EGPIO_audio_ic_power, on);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void
|
||||
irpower(int on)
|
||||
{
|
||||
egpiobits(EGPIO_ir_power, on);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void
|
||||
lcdpower(int on)
|
||||
{
|
||||
egpiobits(EGPIO_lcd_3v|EGPIO_lcd_ic_power|EGPIO_lcd_5v|EGPIO_lcd_9v, on);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void
|
||||
flashprogpower(int on)
|
||||
{
|
||||
egpiobits(EGPIO_prog_flash, on);
|
||||
}
|
||||
|
||||
/* here on hardware reset */
|
||||
void
|
||||
resettrap(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* for drivers that used to run on x86's
|
||||
*/
|
||||
void
|
||||
outb(ulong a, uchar v)
|
||||
{
|
||||
*(uchar*)a = v;
|
||||
}
|
||||
void
|
||||
outs(ulong a, ushort v)
|
||||
{
|
||||
*(ushort*)a = v;
|
||||
}
|
||||
void
|
||||
outss(ulong a, void *p, int n)
|
||||
{
|
||||
ushort *sp = p;
|
||||
|
||||
while(n-- > 0)
|
||||
*(ushort*)a = *sp++;
|
||||
}
|
||||
void
|
||||
outl(ulong a, ulong v)
|
||||
{
|
||||
*(ulong*)a = v;
|
||||
}
|
||||
uchar
|
||||
inb(ulong a)
|
||||
{
|
||||
return *(uchar*)a;
|
||||
}
|
||||
ushort
|
||||
ins(ulong a)
|
||||
{
|
||||
return *(ushort*)a;
|
||||
}
|
||||
void
|
||||
inss(ulong a, void *p, int n)
|
||||
{
|
||||
ushort *sp = p;
|
||||
|
||||
while(n-- > 0)
|
||||
*sp++ = *(ushort*)a;
|
||||
}
|
||||
ulong
|
||||
inl(ulong a)
|
||||
{
|
||||
return *(ulong*)a;
|
||||
}
|
||||
|
||||
char*
|
||||
getconf(char*)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
int
|
||||
cmpswap(long *addr, long old, long new)
|
||||
{
|
||||
int r, s;
|
||||
|
||||
s = splhi();
|
||||
if(r = (*addr==old))
|
||||
*addr = new;
|
||||
splx(s);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
defn acidmap()
|
||||
{
|
||||
local dfoffset;
|
||||
|
||||
dfoffset = map()[1][3];
|
||||
map({"text", _start, etext, 0x20});
|
||||
map({"data", etext+1, edata, dfoffset});
|
||||
print("Set map for plan 9 kernel image\n");
|
||||
print("btext ", _start, " etext ", etext, "\n");
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* Memory and machine-specific definitions. Used in C and assembler.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sizes
|
||||
*/
|
||||
#define BI2BY 8 /* bits per byte */
|
||||
#define BI2WD 32 /* bits per word */
|
||||
#define BY2WD 4 /* bytes per word */
|
||||
#define BY2V 8 /* bytes per double word */
|
||||
#define BY2PG 4096 /* bytes per page */
|
||||
#define WD2PG (BY2PG/BY2WD) /* words per page */
|
||||
#define PGSHIFT 12 /* log(BY2PG) */
|
||||
#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
|
||||
#define PGROUND(s) ROUND(s, BY2PG)
|
||||
#define BLOCKALIGN 8
|
||||
|
||||
#define MAXMACH 1 /* max # cpus system can run */
|
||||
|
||||
/*
|
||||
* Time
|
||||
*/
|
||||
#define HZ (20) /* clock frequency */
|
||||
#define MS2HZ (1000/HZ) /* millisec per clock tick */
|
||||
#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
|
||||
|
||||
/*
|
||||
* Virtual addresses:
|
||||
*
|
||||
* We direct map all discovered DRAM and the area twixt 0xe0000000 and
|
||||
* 0xe8000000 used to provide zeros for cache flushing.
|
||||
*
|
||||
* Flash is mapped to 0xb0000000 and special registers are mapped
|
||||
* on demand to areas starting at 0xa0000000.
|
||||
*
|
||||
* The direct mapping is convenient but not necessary. It means
|
||||
* that we don't have to turn on the MMU till well into the
|
||||
* kernel. This can be changed by providing a mapping in l.s
|
||||
* before calling main.
|
||||
*/
|
||||
#define UZERO 0 /* base of user address space */
|
||||
#define UTZERO (UZERO+BY2PG) /* first address in user text */
|
||||
#define KZERO 0xC0000000 /* base of kernel address space */
|
||||
#define KTZERO 0xC0008000 /* first address in kernel text */
|
||||
#define EMEMZERO 0x90000000 /* 256 meg for add on memory */
|
||||
#define EMEMTOP 0xA0000000 /* ... */
|
||||
#define REGZERO 0xA0000000 /* 128 meg for mapspecial regs */
|
||||
#define REGTOP 0xA8000000 /* ... */
|
||||
#define FLASHZERO 0xB0000000 /* 128 meg for flash */
|
||||
#define FLASHTOP 0xB8000000 /* ... */
|
||||
#define DRAMZERO 0xC0000000 /* 128 meg for dram */
|
||||
#define DRAMTOP 0xC8000000 /* ... */
|
||||
#define UCDRAMZERO 0xC8000000 /* 128 meg for dram (uncached/unbuffered) */
|
||||
#define UCDRAMTOP 0xD0000000 /* ... */
|
||||
#define NULLZERO 0xE0000000 /* 128 meg for cache flush zeroes */
|
||||
#define NULLTOP 0xE8000000 /* ... */
|
||||
#define USTKTOP 0x2000000 /* byte just beyond user stack */
|
||||
#define USTKSIZE (8*1024*1024) /* size of user stack */
|
||||
#define MACHADDR (KZERO+0x00001000)
|
||||
#define EVECTORS 0xFFFF0000 /* virt base of exception vectors */
|
||||
|
||||
#define KSTACK (16*1024) /* Size of kernel stack */
|
||||
|
||||
/*
|
||||
* Offsets into flash
|
||||
*/
|
||||
#define Flash_bootldr (FLASHZERO+0x0) /* boot loader */
|
||||
#define Flash_kernel (FLASHZERO+0x10000) /* boot kernel */
|
||||
#define Flash_tar (FLASHZERO+0x200000) /* fs.sac (tar file) */
|
||||
|
||||
/*
|
||||
* virtual MMU
|
||||
*/
|
||||
#define PTEMAPMEM (1024*1024)
|
||||
#define PTEPERTAB (PTEMAPMEM/BY2PG)
|
||||
#define SEGMAPSIZE 1984
|
||||
#define SSEGMAPSIZE 16
|
||||
#define PPN(x) ((x)&~(BY2PG-1))
|
||||
|
||||
/*
|
||||
* SA1110 definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* memory physical addresses
|
||||
*/
|
||||
#define PHYSFLASH0 0x00000000
|
||||
#define PHYSDRAM0 0xC0000000
|
||||
#define PHYSNULL0 0xE0000000
|
||||
|
||||
/*
|
||||
* peripheral control module physical addresses
|
||||
*/
|
||||
#define USBREGS 0x80000000 /* serial port 0 - USB */
|
||||
#define UART1REGS 0x80010000 /* serial port 1 - UART */
|
||||
#define GPCLKREGS 0x80020060 /* serial port 1 - general purpose clock */
|
||||
#define UART2REGS 0x80030000 /* serial port 2 - low speed IR */
|
||||
#define HSSPREGS 0x80040060 /* serial port 2 - high speed IR */
|
||||
#define UART3REGS 0x80050000 /* serial port 3 - RS232 UART */
|
||||
#define MCPREGS 0x80060000 /* serial port 4 - multimedia comm port */
|
||||
#define SSPREGS 0x80070060 /* serial port 4 - synchronous serial port */
|
||||
#define OSTIMERREGS 0x90000000 /* operating system timer registers */
|
||||
#define POWERREGS 0x90020000 /* power management */
|
||||
#define RESETREGS 0x90030000 /* reset controller */
|
||||
#define GPIOREGS 0x90040000 /* 28 general purpose IO pins */
|
||||
#define INTRREGS 0x90050000 /* interrupt registers */
|
||||
#define PPCREGS 0x90060000 /* peripheral pin controller */
|
||||
#define MEMCONFREGS 0xA0000000 /* memory configuration */
|
||||
#define LCDREGS 0xB0100000 /* display */
|
||||
|
||||
/*
|
||||
* PCMCIA addresses
|
||||
*/
|
||||
#define PHYSPCM0REGS 0x20000000
|
||||
#define PYHSPCM0ATTR 0x28000000
|
||||
#define PYHSPCM0MEM 0x2C000000
|
||||
#define PHYSPCM1REGS 0x30000000
|
||||
#define PYHSPCM1ATTR 0x38000000
|
||||
#define PYHSPCM1MEM 0x3C000000
|
||||
|
||||
/*
|
||||
* Program Status Registers
|
||||
*/
|
||||
#define PsrMusr 0x00000010 /* mode */
|
||||
#define PsrMfiq 0x00000011
|
||||
#define PsrMirq 0x00000012
|
||||
#define PsrMsvc 0x00000013
|
||||
#define PsrMabt 0x00000017
|
||||
#define PsrMund 0x0000001B
|
||||
#define PsrMask 0x0000001F
|
||||
|
||||
#define PsrDfiq 0x00000040 /* disable FIQ interrupts */
|
||||
#define PsrDirq 0x00000080 /* disable IRQ interrupts */
|
||||
|
||||
#define PsrV 0x10000000 /* overflow */
|
||||
#define PsrC 0x20000000 /* carry/borrow/extend */
|
||||
#define PsrZ 0x40000000 /* zero */
|
||||
#define PsrN 0x80000000 /* negative/less than */
|
||||
|
||||
/*
|
||||
* Coprocessors
|
||||
*/
|
||||
#define CpMMU 15
|
||||
#define CpPWR 15
|
||||
|
||||
/*
|
||||
* Internal MMU coprocessor registers
|
||||
*/
|
||||
#define CpCPUID 0 /* R: */
|
||||
#define CpControl 1 /* RW: */
|
||||
#define CpTTB 2 /* RW: translation table base */
|
||||
#define CpDAC 3 /* RW: domain access control */
|
||||
#define CpFSR 5 /* RW: fault status */
|
||||
#define CpFAR 6 /* RW: fault address */
|
||||
#define CpCacheFlush 7 /* W: cache flushing, wb draining*/
|
||||
#define CpTLBFlush 8 /* W: TLB flushing */
|
||||
#define CpRBFlush 9 /* W: Read Buffer ops */
|
||||
#define CpPID 13 /* RW: PID for virtual mapping */
|
||||
#define CpBpt 14 /* W: Breakpoint register */
|
||||
#define CpTest 15 /* W: Test, Clock and Idle Control */
|
||||
|
||||
/*
|
||||
* CpControl
|
||||
*/
|
||||
#define CpCmmuena 0x00000001 /* M: MMU enable */
|
||||
#define CpCalign 0x00000002 /* A: alignment fault enable */
|
||||
#define CpCdcache 0x00000004 /* C: data cache on */
|
||||
#define CpCwb 0x00000008 /* W: write buffer turned on */
|
||||
#define CpCi32 0x00000010 /* P: 32-bit program space */
|
||||
#define CpCd32 0x00000020 /* D: 32-bit data space */
|
||||
#define CpCbe 0x00000080 /* B: big-endian operation */
|
||||
#define CpCsystem 0x00000100 /* S: system permission */
|
||||
#define CpCrom 0x00000200 /* R: ROM permission */
|
||||
#define CpCicache 0x00001000 /* I: instruction cache on */
|
||||
#define CpCvivec 0x00002000 /* X: virtual interrupt vector adjust */
|
||||
|
||||
/*
|
||||
* fault codes
|
||||
*/
|
||||
#define FCterm 0x2 /* terminal */
|
||||
#define FCvec 0x0 /* vector */
|
||||
#define FCalignf 0x1 /* unaligned full word data access */
|
||||
#define FCalignh 0x3 /* unaligned half word data access */
|
||||
#define FCl1abort 0xc /* level 1 external abort on translation */
|
||||
#define FCl2abort 0xe /* level 2 external abort on translation */
|
||||
#define FCtransSec 0x5 /* section translation */
|
||||
#define FCtransPage 0x7 /* page translation */
|
||||
#define FCdomainSec 0x9 /* section domain */
|
||||
#define FCdomainPage 0x11 /* page domain */
|
||||
#define FCpermSec 0x9 /* section permissions */
|
||||
#define FCpermPage 0x11 /* page permissions */
|
||||
#define FCabortLFSec 0x4 /* external abort on linefetch for section */
|
||||
#define FCabortLFPage 0x6 /* external abort on linefetch for page */
|
||||
#define FCabortNLFSec 0x8 /* external abort on non-linefetch for section */
|
||||
#define FCabortNLFPage 0xa /* external abort on non-linefetch for page */
|
||||
|
||||
/*
|
||||
* PTE bits used by fault.h. mmu.c translates them to real values.
|
||||
*/
|
||||
#define PTEVALID (1<<0)
|
||||
#define PTERONLY 0 /* this is implied by the absence of PTEWRITE */
|
||||
#define PTEWRITE (1<<1)
|
||||
#define PTEUNCACHED (1<<2)
|
||||
#define PTEKERNEL (1<<3) /* no user access */
|
||||
|
||||
/*
|
||||
* H3650 specific definitions
|
||||
*/
|
||||
#define EGPIOREGS 0x49000000 /* Additional GPIO register */
|
||||
|
||||
/* Power management */
|
||||
|
||||
#define PWR_rtc 0x80000000 /* resume on RTC */
|
||||
#define PWR_gpio0 0x00000001 /* resume on power button */
|
||||
|
||||
#define RCSR_all 0x0000000f
|
||||
#define PCFR_opde 0x00000001 /* oscillator power-down enable */
|
||||
#define PCFR_suspend 0x00000001
|
||||
#define PCFR_fp 0x00000002 /* float pcmcia */
|
||||
#define PCFR_fs 0x00000004 /* float static memory */
|
||||
#define PCFR_fo 0x00000008
|
||||
|
||||
#define MDREFR_k1db2 (1 << 22)
|
||||
#define MDREFR_slfrsh 0x80000000 /* self refresh */
|
||||
#define MDREFR_e1pin (1 << 20)
|
||||
#define MSC_rt 0x00030003
|
||||
|
||||
#define MDCNFG_de0 0x00000001 /* dram enable */
|
||||
#define MDCNFG_de1 0x00000002
|
||||
#define MDCNFG_de2 0x00000004
|
||||
#define MDCNFG_de3 0x00000008
|
||||
#define MDCFNG_de 0x0000000f
|
||||
#define PMCR_sf 1
|
|
@ -1,139 +0,0 @@
|
|||
CONF=bitsy
|
||||
CONFLIST=bitsy
|
||||
|
||||
objtype=arm
|
||||
</$objtype/mkfile
|
||||
p=9
|
||||
|
||||
DEVS=`{rc ../port/mkdevlist $CONF}
|
||||
|
||||
PORT=\
|
||||
alarm.$O\
|
||||
alloc.$O\
|
||||
allocb.$O\
|
||||
auth.$O\
|
||||
cache.$O\
|
||||
chan.$O\
|
||||
dev.$O\
|
||||
edf.$O\
|
||||
fault.$O\
|
||||
mul64fract.$O\
|
||||
rebootcmd.$O\
|
||||
page.$O\
|
||||
parse.$O\
|
||||
pgrp.$O\
|
||||
portclock.$O\
|
||||
print.$O\
|
||||
proc.$O\
|
||||
qio.$O\
|
||||
qlock.$O\
|
||||
segment.$O\
|
||||
swap.$O\
|
||||
sysfile.$O\
|
||||
sysproc.$O\
|
||||
taslock.$O\
|
||||
tod.$O\
|
||||
xalloc.$O\
|
||||
random.$O\
|
||||
|
||||
OBJ=\
|
||||
l.$O\
|
||||
clock.$O\
|
||||
defont.$O\
|
||||
fpi.$O\
|
||||
fpiarm.$O\
|
||||
fpimem.$O\
|
||||
main.$O\
|
||||
mmu.$O\
|
||||
power.$O\
|
||||
sa1110dma.$O\
|
||||
screen.$O\
|
||||
trap.$O\
|
||||
$CONF.root.$O\
|
||||
$CONF.rootc.$O\
|
||||
$DEVS\
|
||||
$PORT\
|
||||
|
||||
LIB=\
|
||||
/$objtype/lib/libmemlayer.a\
|
||||
/$objtype/lib/libmemdraw.a\
|
||||
/$objtype/lib/libdraw.a\
|
||||
/$objtype/lib/libip.a\
|
||||
/$objtype/lib/libc.a\
|
||||
/$objtype/lib/libsec.a\
|
||||
/$objtype/lib/libip.a\
|
||||
|
||||
size:VQ: $p$CONF
|
||||
ls -l $p$CONF|sed 's/^[^ ]+ [^ ]+ [^ ]+ [^ ]+ [^ ]+ ([^ ]+).*/load ram 0xc0008000 \1/'
|
||||
echo load kernel
|
||||
echo !xms /sys/src/9/bitsy/^$p$CONF
|
||||
echo jump 0xc0008010
|
||||
|
||||
acid:VQ:
|
||||
echo acid -lmap s9bitsy
|
||||
|
||||
$p$CONF: $OBJ $CONF.c $LIB /arm/inflate
|
||||
$CC $CFLAGS '-DKERNDATE='`{date -n} $CONF.c
|
||||
$LD -o $target -H5 -R4 -T0xC0008010 -l $OBJ $CONF.$O $LIB
|
||||
$LD -o s$target -R4 -T0xC0008010 -l $OBJ $CONF.$O $LIB
|
||||
gzip $target
|
||||
cat /arm/inflate $target.gz > $target
|
||||
echo the boot loader misses the last 12 bytes >> $target
|
||||
rm $target.gz
|
||||
|
||||
install:V: $p$CONF paqdisk
|
||||
if(test -d /n/once/arm){
|
||||
cp $p$CONF /n/once/arm/$p$CONF
|
||||
cp s$p$CONF /n/once/arm/s$p$CONF
|
||||
cp paqdisk /n/once/arm/paqdisk
|
||||
}
|
||||
if not
|
||||
status=''
|
||||
# 9fs lookout && cp $p$CONF /n/lookout/$objtype/$p$CONF
|
||||
|
||||
installkern:V: $p$CONF
|
||||
cp $p$CONF /$objtype/$p$CONF
|
||||
cp s$p$CONF /$objtype/s$p$CONF
|
||||
|
||||
<../boot/bootmkfile
|
||||
<../port/portmkfile
|
||||
<|../port/mkbootrules $CONF
|
||||
|
||||
init.h:D: ../port/initcode.c init9.s
|
||||
$CC ../port/initcode.c
|
||||
$AS init9.s
|
||||
$LD -l -R1 -s -o init.out init9.$O initcode.$O /arm/lib/libc.a
|
||||
{echo 'uchar initcode[]={'
|
||||
xd -1x <init.out |
|
||||
sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
|
||||
echo '};'} > init.h
|
||||
|
||||
clock.$O: /$objtype/include/ureg.h
|
||||
devether.$O: /$objtype/include/ureg.h ../port/netif.h
|
||||
devpcmcia.$O: /$objtype/include/ureg.h
|
||||
fpi.$O: fpi.h
|
||||
fpiarm.$O: /$objtype/include/ureg.h fpi.h
|
||||
fpimem.$O: fpi.h
|
||||
main.$O: /$objtype/include/ureg.h errstr.h init.h
|
||||
mmu.$O: /$objtype/include/ureg.h
|
||||
power.$O: /$objtype/include/ureg.h
|
||||
scu.$O: /$objtype/include/ureg.h
|
||||
sa1110dma.$O: /$objtype/include/ureg.h
|
||||
screen.$O: gamma.h
|
||||
sdata.$O: /$objtype/include/ureg.h
|
||||
trap$O: /$objtype/include/ureg.h
|
||||
wavelan.$O: /$objtype/include/ureg.h wavelan.c wavelan.h ../pc/wavelan.h
|
||||
|
||||
paqdisk:V:
|
||||
rm -fr armpaq
|
||||
mkdir armpaq
|
||||
cd armpaq
|
||||
disk/mkfs -d . /sys/lib/sysconfig/proto/armpaqproto
|
||||
mkpaqfs -o ../paqdisk
|
||||
cd ..
|
||||
echo load ramdisk
|
||||
echo !xms /sys/src/9/bitsy/paqdisk
|
||||
|
||||
bitsy.clean:
|
||||
rm -rf armpaq $p$CONF s$p$CONF paqdisk $CONF.c boot$CONF.c ../boot/libboot.a5
|
||||
|
|
@ -1,532 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
/*
|
||||
* to avoid mmu and cash flushing, we use the pid register in the MMU
|
||||
* to map all user addresses. Although there are 64 possible pids, we
|
||||
* can only use 31 because there are only 32 protection domains and we
|
||||
* need one for the kernel. Pid i is thus associated with domain i.
|
||||
* Domain 0 is used for the kernel.
|
||||
*/
|
||||
|
||||
/* real protection bits */
|
||||
enum
|
||||
{
|
||||
/* level 1 descriptor bits */
|
||||
L1TypeMask= (3<<0),
|
||||
L1Invalid= (0<<0),
|
||||
L1PageTable= (1<<0),
|
||||
L1Section= (2<<0),
|
||||
L1Cached= (1<<3),
|
||||
L1Buffered= (1<<2),
|
||||
L1DomShift= 5,
|
||||
L1Domain0= (0<<L1DomShift),
|
||||
L1KernelRO= (0x0<<10),
|
||||
L1KernelRW= (0x1<<10),
|
||||
L1UserRO= (0x2<<10),
|
||||
L1UserRW= (0x3<<10),
|
||||
L1SectBaseMask= (0xFFF<<20),
|
||||
L1PTBaseMask= (0x3FFFFF<<10),
|
||||
|
||||
/* level 2 descriptor bits */
|
||||
L2TypeMask= (3<<0),
|
||||
L2SmallPage= (2<<0),
|
||||
L2LargePage= (1<<0),
|
||||
L2Cached= (1<<3),
|
||||
L2Buffered= (1<<2),
|
||||
L2KernelRW= (0x55<<4),
|
||||
L2UserRO= (0xAA<<4),
|
||||
L2UserRW= (0xFF<<4),
|
||||
L2PageBaseMask= (0xFFFFF<<12),
|
||||
|
||||
/* domain values */
|
||||
Dnoaccess= 0,
|
||||
Dclient= 1,
|
||||
Dmanager= 3,
|
||||
};
|
||||
|
||||
ulong *l1table;
|
||||
static int mmuinited;
|
||||
|
||||
/*
|
||||
* We map all of memory, flash, and the zeros area with sections.
|
||||
* Special use space is mapped on the fly with regmap.
|
||||
*/
|
||||
void
|
||||
mmuinit(void)
|
||||
{
|
||||
ulong a, o;
|
||||
ulong *t;
|
||||
|
||||
/* get a prototype level 1 page */
|
||||
l1table = xspanalloc(16*1024, 16*1024, 0);
|
||||
memset(l1table, 0, 16*1024);
|
||||
|
||||
/* map low mem (I really don't know why I have to do this -- presotto) */
|
||||
for(o = 0; o < 1*OneMeg; o += OneMeg)
|
||||
l1table[(0+o)>>20] = L1Section | L1KernelRW| L1Domain0
|
||||
| L1Cached | L1Buffered
|
||||
| ((0+o)&L1SectBaseMask);
|
||||
|
||||
/* map DRAM */
|
||||
for(o = 0; o < DRAMTOP-DRAMZERO; o += OneMeg)
|
||||
l1table[(DRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0
|
||||
| L1Cached | L1Buffered
|
||||
| ((PHYSDRAM0+o)&L1SectBaseMask);
|
||||
|
||||
/* uncached DRAM */
|
||||
for(o = 0; o < UCDRAMTOP-UCDRAMZERO; o += OneMeg)
|
||||
l1table[(UCDRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0
|
||||
| ((PHYSDRAM0+o)&L1SectBaseMask);
|
||||
|
||||
/* map zeros area */
|
||||
for(o = 0; o < NULLTOP-NULLZERO; o += OneMeg)
|
||||
l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0
|
||||
| L1Cached | L1Buffered
|
||||
| ((PHYSNULL0+o)&L1SectBaseMask);
|
||||
|
||||
/* map flash */
|
||||
for(o = 0; o < FLASHTOP-FLASHZERO; o += OneMeg)
|
||||
l1table[(FLASHZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0
|
||||
| ((PHYSFLASH0+o)&L1SectBaseMask);
|
||||
|
||||
/* map peripheral control module regs */
|
||||
mapspecial(0x80000000, OneMeg);
|
||||
|
||||
/* map system control module regs */
|
||||
mapspecial(0x90000000, OneMeg);
|
||||
|
||||
/*
|
||||
* double map start of ram to exception vectors
|
||||
*/
|
||||
a = EVECTORS;
|
||||
t = xspanalloc(BY2PG, 1024, 0);
|
||||
memset(t, 0, BY2PG);
|
||||
l1table[a>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask);
|
||||
t[(a&0xfffff)>>PGSHIFT] = L2SmallPage | L2KernelRW | (PHYSDRAM0 & L2PageBaseMask);
|
||||
|
||||
mmurestart();
|
||||
|
||||
mmuinited = 1;
|
||||
}
|
||||
|
||||
void
|
||||
mmurestart(void) {
|
||||
/* set up the domain register to cause all domains to obey pte access bits */
|
||||
|
||||
putdac(Dclient);
|
||||
|
||||
/* point to map */
|
||||
putttb((ulong)l1table);
|
||||
|
||||
/* enable mmu */
|
||||
wbflush();
|
||||
mmuinvalidate();
|
||||
mmuenable();
|
||||
cacheflush();
|
||||
}
|
||||
|
||||
/*
|
||||
* map on request
|
||||
*/
|
||||
static void*
|
||||
_map(ulong pa, int len, ulong zero, ulong top, ulong l1prop, ulong l2prop)
|
||||
{
|
||||
ulong *t;
|
||||
ulong va, i, base, end, off, entry;
|
||||
int large;
|
||||
ulong* rv;
|
||||
|
||||
rv = nil;
|
||||
large = len >= 128*1024;
|
||||
if(large){
|
||||
base = pa & ~(OneMeg-1);
|
||||
end = (pa+len-1) & ~(OneMeg-1);
|
||||
} else {
|
||||
base = pa & ~(BY2PG-1);
|
||||
end = (pa+len-1) & ~(BY2PG-1);
|
||||
}
|
||||
off = pa - base;
|
||||
|
||||
for(va = zero; va < top && base <= end; va += OneMeg){
|
||||
switch(l1table[va>>20] & L1TypeMask){
|
||||
default:
|
||||
/* found unused entry on level 1 table */
|
||||
if(large){
|
||||
if(rv == nil)
|
||||
rv = (ulong*)(va+off);
|
||||
l1table[va>>20] = L1Section | l1prop | L1Domain0 |
|
||||
(base & L1SectBaseMask);
|
||||
base += OneMeg;
|
||||
continue;
|
||||
} else {
|
||||
|
||||
/* create an L2 page table and keep going */
|
||||
t = xspanalloc(BY2PG, 1024, 0);
|
||||
memset(t, 0, BY2PG);
|
||||
l1table[va>>20] = L1PageTable | L1Domain0 |
|
||||
(((ulong)t) & L1PTBaseMask);
|
||||
}
|
||||
break;
|
||||
case L1Section:
|
||||
/* if it's already mapped in a one meg area, don't remap */
|
||||
entry = l1table[va>>20];
|
||||
i = entry & L1SectBaseMask;
|
||||
if(pa >= i && (pa+len) <= i + OneMeg)
|
||||
if((entry & ~L1SectBaseMask) == (L1Section | l1prop | L1Domain0))
|
||||
return (void*)(va + (pa & (OneMeg-1)));
|
||||
|
||||
continue;
|
||||
case L1PageTable:
|
||||
if(large)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
/* here if we're using page maps instead of sections */
|
||||
t = (ulong*)(l1table[va>>20] & L1PTBaseMask);
|
||||
for(i = 0; i < OneMeg && base <= end; i += BY2PG){
|
||||
entry = t[i>>PGSHIFT];
|
||||
|
||||
/* found unused entry on level 2 table */
|
||||
if((entry & L2TypeMask) != L2SmallPage){
|
||||
if(rv == nil)
|
||||
rv = (ulong*)(va+i+off);
|
||||
t[i>>PGSHIFT] = L2SmallPage | l2prop |
|
||||
(base & L2PageBaseMask);
|
||||
base += BY2PG;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* didn't fit */
|
||||
if(base <= end)
|
||||
return nil;
|
||||
cacheflush();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* map in i/o registers */
|
||||
void*
|
||||
mapspecial(ulong pa, int len)
|
||||
{
|
||||
return _map(pa, len, REGZERO, REGTOP, L1KernelRW, L2KernelRW);
|
||||
}
|
||||
|
||||
/* map add on memory */
|
||||
void*
|
||||
mapmem(ulong pa, int len, int cached)
|
||||
{
|
||||
ulong l1, l2;
|
||||
|
||||
if(cached){
|
||||
l1 = L1KernelRW|L1Cached|L1Buffered;
|
||||
l2 = L2KernelRW|L2Cached|L2Buffered;
|
||||
} else {
|
||||
l1 = L1KernelRW;
|
||||
l2 = L2KernelRW;
|
||||
}
|
||||
return _map(pa, len, EMEMZERO, EMEMTOP, l1, l2);
|
||||
}
|
||||
|
||||
/* map a virtual address to a physical one */
|
||||
ulong
|
||||
mmu_paddr(ulong va)
|
||||
{
|
||||
ulong entry;
|
||||
ulong *t;
|
||||
|
||||
entry = l1table[va>>20];
|
||||
switch(entry & L1TypeMask){
|
||||
case L1Section:
|
||||
return (entry & L1SectBaseMask) | (va & (OneMeg-1));
|
||||
case L1PageTable:
|
||||
t = (ulong*)(entry & L1PTBaseMask);
|
||||
va &= OneMeg-1;
|
||||
entry = t[va>>PGSHIFT];
|
||||
switch(entry & L1TypeMask){
|
||||
case L2SmallPage:
|
||||
return (entry & L2PageBaseMask) | (va & (BY2PG-1));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* map a physical address to a virtual one */
|
||||
ulong
|
||||
findva(ulong pa, ulong zero, ulong top)
|
||||
{
|
||||
int i;
|
||||
ulong entry, va;
|
||||
ulong start, end;
|
||||
ulong *t;
|
||||
|
||||
for(va = zero; va < top; va += OneMeg){
|
||||
/* search the L1 entry */
|
||||
entry = l1table[va>>20];
|
||||
switch(entry & L1TypeMask){
|
||||
default:
|
||||
return 0; /* no holes */
|
||||
case L1Section:
|
||||
start = entry & L1SectBaseMask;
|
||||
end = start + OneMeg;
|
||||
if(pa >= start && pa < end)
|
||||
return va | (pa & (OneMeg-1));
|
||||
continue;
|
||||
case L1PageTable:
|
||||
break;
|
||||
}
|
||||
|
||||
/* search the L2 entry */
|
||||
t = (ulong*)(l1table[va>>20] & L1PTBaseMask);
|
||||
for(i = 0; i < OneMeg; i += BY2PG){
|
||||
entry = t[i>>PGSHIFT];
|
||||
|
||||
/* found unused entry on level 2 table */
|
||||
if((entry & L2TypeMask) != L2SmallPage)
|
||||
break;
|
||||
|
||||
start = entry & L2PageBaseMask;
|
||||
end = start + BY2PG;
|
||||
if(pa >= start && pa < end)
|
||||
return va | (BY2PG*i) | (pa & (BY2PG-1));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ulong
|
||||
mmu_kaddr(ulong pa)
|
||||
{
|
||||
ulong va;
|
||||
|
||||
/* try the easy stuff first (the first case is true most of the time) */
|
||||
if(pa >= PHYSDRAM0 && pa <= PHYSDRAM0+(DRAMTOP-DRAMZERO))
|
||||
return DRAMZERO+(pa-PHYSDRAM0);
|
||||
if(pa >= PHYSFLASH0 && pa <= PHYSFLASH0+(FLASHTOP-FLASHZERO))
|
||||
return FLASHZERO+(pa-PHYSFLASH0);
|
||||
if(pa >= PHYSNULL0 && pa <= PHYSNULL0+(NULLTOP-NULLZERO))
|
||||
return NULLZERO+(pa-PHYSNULL0);
|
||||
|
||||
if(!mmuinited)
|
||||
return 0; /* this shouldn't happen */
|
||||
|
||||
/* walk the map for the special regs and extended memory */
|
||||
va = findva(pa, EMEMZERO, EMEMTOP);
|
||||
if(va != 0)
|
||||
return va;
|
||||
return findva(pa, REGZERO, REGTOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of bytes that can be accessed via KADDR(pa).
|
||||
* If pa is not a valid argument to KADDR, return 0.
|
||||
*/
|
||||
ulong
|
||||
cankaddr(ulong pa)
|
||||
{
|
||||
/*
|
||||
* Is this enough?
|
||||
* We'll find out if anyone still has one
|
||||
* of these...
|
||||
*/
|
||||
if(pa >= PHYSDRAM0 && pa <= PHYSDRAM0+(DRAMTOP-DRAMZERO))
|
||||
return PHYSDRAM0+(DRAMTOP-DRAMZERO) - pa;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* table to map fault.c bits to physical bits
|
||||
*/
|
||||
static ulong mmubits[16] =
|
||||
{
|
||||
[PTEVALID] L2SmallPage|L2Cached|L2Buffered|L2UserRO,
|
||||
[PTEVALID|PTEWRITE] L2SmallPage|L2Cached|L2Buffered|L2UserRW,
|
||||
[PTEVALID|PTEUNCACHED] L2SmallPage|L2UserRO,
|
||||
[PTEVALID|PTEUNCACHED|PTEWRITE] L2SmallPage|L2UserRW,
|
||||
|
||||
[PTEKERNEL|PTEVALID] L2SmallPage|L2Cached|L2Buffered|L2KernelRW,
|
||||
[PTEKERNEL|PTEVALID|PTEWRITE] L2SmallPage|L2Cached|L2Buffered|L2KernelRW,
|
||||
[PTEKERNEL|PTEVALID|PTEUNCACHED] L2SmallPage|L2KernelRW,
|
||||
[PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE] L2SmallPage|L2KernelRW,
|
||||
};
|
||||
|
||||
/*
|
||||
* add an entry to the current map
|
||||
*/
|
||||
void
|
||||
putmmu(uintptr va, uintptr pa, Page *pg)
|
||||
{
|
||||
Page *l2pg;
|
||||
ulong *t, *l1p, *l2p;
|
||||
int s;
|
||||
|
||||
s = splhi();
|
||||
|
||||
/* clear out the current entry */
|
||||
mmuinvalidateaddr(va);
|
||||
|
||||
l2pg = up->l1page[va>>20];
|
||||
if(l2pg == nil){
|
||||
l2pg = up->mmufree;
|
||||
if(l2pg != nil){
|
||||
up->mmufree = l2pg->next;
|
||||
} else {
|
||||
splx(s);
|
||||
l2pg = newpage(0, 0, 0);
|
||||
splhi();
|
||||
}
|
||||
l2pg->va = VA(kmap(l2pg));
|
||||
up->l1page[va>>20] = l2pg;
|
||||
memset((uchar*)(l2pg->va), 0, BY2PG);
|
||||
}
|
||||
|
||||
/* always point L1 entry to L2 page, can't hurt */
|
||||
l1p = &l1table[va>>20];
|
||||
*l1p = L1PageTable | L1Domain0 | (l2pg->pa & L1PTBaseMask);
|
||||
up->l1table[va>>20] = *l1p;
|
||||
t = (ulong*)l2pg->va;
|
||||
|
||||
/* set L2 entry */
|
||||
l2p = &t[(va & (OneMeg-1))>>PGSHIFT];
|
||||
*l2p = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)]
|
||||
| (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE));
|
||||
|
||||
/* write back dirty entries - we need this because the pio() in
|
||||
* fault.c is writing via a different virt addr and won't clean
|
||||
* its changes out of the dcache. Page coloring doesn't work
|
||||
* on this mmu because the virtual cache is set associative
|
||||
* rather than direct mapped.
|
||||
*/
|
||||
cachewb();
|
||||
if(pg->txtflush){
|
||||
icacheinvalidate();
|
||||
pg->txtflush = 0;
|
||||
}
|
||||
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* free up all page tables for this proc
|
||||
*/
|
||||
void
|
||||
mmuptefree(Proc *p)
|
||||
{
|
||||
Page *pg;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < Nmeg; i++){
|
||||
pg = p->l1page[i];
|
||||
if(pg == nil)
|
||||
continue;
|
||||
p->l1page[i] = nil;
|
||||
pg->next = p->mmufree;
|
||||
p->mmufree = pg;
|
||||
}
|
||||
memset(p->l1table, 0, sizeof(p->l1table));
|
||||
}
|
||||
|
||||
/*
|
||||
* this is called with palloc locked so the pagechainhead is kosher
|
||||
*/
|
||||
void
|
||||
mmurelease(Proc* p)
|
||||
{
|
||||
Page *pg, *next;
|
||||
|
||||
/* write back dirty cache entries before changing map */
|
||||
cacheflush();
|
||||
|
||||
mmuptefree(p);
|
||||
|
||||
for(pg = p->mmufree; pg != nil; pg = next){
|
||||
next = pg->next;
|
||||
if(--pg->ref)
|
||||
panic("mmurelease: pg->ref %d\n", pg->ref);
|
||||
pagechainhead(pg);
|
||||
}
|
||||
if(p->mmufree != nil)
|
||||
pagechaindone();
|
||||
p->mmufree = nil;
|
||||
|
||||
memset(l1table, 0, sizeof(p->l1table));
|
||||
cachewbregion((ulong)l1table, sizeof(p->l1table));
|
||||
}
|
||||
|
||||
void
|
||||
mmuswitch(Proc *p)
|
||||
{
|
||||
if(m->mmupid == p->pid && p->newtlb == 0)
|
||||
return;
|
||||
m->mmupid = p->pid;
|
||||
|
||||
/* write back dirty cache entries and invalidate all cache entries */
|
||||
cacheflush();
|
||||
|
||||
if(p->newtlb){
|
||||
mmuptefree(p);
|
||||
p->newtlb = 0;
|
||||
}
|
||||
|
||||
/* move in new map */
|
||||
memmove(l1table, p->l1table, sizeof(p->l1table));
|
||||
|
||||
/* make sure map is in memory */
|
||||
cachewbregion((ulong)l1table, sizeof(p->l1table));
|
||||
|
||||
/* lose any possible stale tlb entries */
|
||||
mmuinvalidate();
|
||||
}
|
||||
|
||||
void
|
||||
flushmmu(void)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splhi();
|
||||
up->newtlb = 1;
|
||||
mmuswitch(up);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
peekmmu(ulong va)
|
||||
{
|
||||
ulong e, d;
|
||||
|
||||
e = l1table[va>>20];
|
||||
switch(e & L1TypeMask){
|
||||
default:
|
||||
iprint("l1: %#p[%#lux] = %#lux invalid\n", l1table, va>>20, e);
|
||||
break;
|
||||
case L1PageTable:
|
||||
iprint("l1: %#p[%#lux] = %#lux pt\n", l1table, va>>20, e);
|
||||
va &= OneMeg-1;
|
||||
va >>= PGSHIFT;
|
||||
e &= L1PTBaseMask;
|
||||
d = ((ulong*)e)[va];
|
||||
iprint("l2: %#lux[%#lux] = %#lux\n", e, va, d);
|
||||
break;
|
||||
case L1Section:
|
||||
iprint("l1: %#p[%#lux] = %#lux section\n", l1table, va>>20, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
checkmmu(uintptr, uintptr)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
countpagerefs(ulong*, int)
|
||||
{
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
#include "io.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
|
||||
enum {
|
||||
Button1 = 0x1;
|
||||
Button2 = 0x2;
|
||||
Button3 = 0x4;
|
||||
};
|
||||
|
||||
int buttons;
|
||||
Point position;
|
||||
|
||||
static void
|
||||
mousevent(void) {
|
||||
static int curbuttons;
|
||||
static Point curposition;
|
||||
|
||||
if (buttons == curbuttons && eqpt(position, curposition))
|
||||
return;
|
||||
|
||||
/* generate a mouse event */
|
||||
curbuttons = buttons;
|
||||
curposition = position;
|
||||
}
|
||||
|
||||
void
|
||||
buttonevent(int event) {
|
||||
switch (event) {
|
||||
case 0x02:
|
||||
/* Button 2 down */
|
||||
buttons |= Button2;
|
||||
mousevent();
|
||||
break;
|
||||
case 0x82:
|
||||
/* Button 2 up */
|
||||
buttons &= ~Button2;
|
||||
mousevent();
|
||||
break;
|
||||
case 0x03:
|
||||
/* Button 3 down */
|
||||
buttons |= Button3;
|
||||
mousevent();
|
||||
break;
|
||||
case 0x83:
|
||||
/* Button 3 up */
|
||||
buttons &= ~Button3;
|
||||
mousevent();
|
||||
break;
|
||||
default:
|
||||
/* other buttons */
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
#!/bin/rc
|
||||
|
||||
debug=0
|
||||
|
||||
#set service to terminal (necessary for factotum, handy for everything else)
|
||||
service=terminal
|
||||
|
||||
echo -n terminal > /env/service
|
||||
echo -n plan9 > /env/site
|
||||
echo -n astro > /env/facedom
|
||||
echo -n emelie > /env/fs
|
||||
|
||||
bind -a '#y' /dev
|
||||
bind -a '#F' /dev
|
||||
bind -a '#I' /net
|
||||
bind -a '#D' /net
|
||||
|
||||
# parallelism for mk
|
||||
NPROC=1
|
||||
|
||||
sysname=`{cat /dev/sysname}
|
||||
if (~ $sysname ''){
|
||||
sysname=bitsy
|
||||
echo $sysname>/dev/sysname
|
||||
}
|
||||
prompt=($sysname^'# ' ' ')
|
||||
|
||||
# flavor
|
||||
fileserver=emelie
|
||||
cpu=olive
|
||||
|
||||
# user defined flash partitions
|
||||
echo -n add fs 0x0800000 0x1000000 > /dev/flash/flashctl
|
||||
|
||||
# so we can see things
|
||||
light 0
|
||||
|
||||
# set variables
|
||||
if(~ $debug 1) echo ramfs
|
||||
ramfs
|
||||
if(~ $debug 1) echo pencal
|
||||
params -f
|
||||
if(! grep -s '^calibrate=' /tmp/tmpparams)
|
||||
pencal >>/tmp/tmpparams
|
||||
if not {
|
||||
eval `{grep '^calibrate=' /tmp/tmpparams}
|
||||
echo calibrate $calibrate > '#m/mousectl'
|
||||
}
|
||||
prompter /tmp/tmpparams
|
||||
params
|
||||
if(~ $debug 1) {
|
||||
echo tmpparams:
|
||||
cat /tmp/tmpparams
|
||||
}
|
||||
. /tmp/tmpparams
|
||||
|
||||
if(~ $debug 1) echo set user
|
||||
# set userid
|
||||
if(test -e /env/user){
|
||||
echo -n $user > /dev/hostowner
|
||||
}
|
||||
|
||||
if(~ $debug 1) echo start flashfs
|
||||
# bind in read/write file system
|
||||
if (aux/flashfs) {
|
||||
if (~ $debug 1) echo flashfs started
|
||||
mount /srv/brzr /n/tmp
|
||||
bind -a /n /n/tmp/n
|
||||
bind -a /sys/lib /n/tmp/sys/lib
|
||||
bind -a /sys /n/tmp/sys
|
||||
bind -a /arm/bin/auth /n/tmp/arm/bin/auth
|
||||
bind -a /arm/bin/ndb /n/tmp/arm/bin/ndb
|
||||
bind -a /arm/bin/ip /n/tmp/arm/bin/ip
|
||||
bind -a /arm/bin/aux /n/tmp/arm/bin/aux
|
||||
bind -a /arm/bin /n/tmp/arm/bin
|
||||
bind -a /arm /n/tmp/arm
|
||||
bind -a /lib/ndb /n/tmp/lib/ndb
|
||||
bind -a /lib/font /n/tmp/lib/font
|
||||
bind -a /lib /n/tmp/lib
|
||||
bind -a / /n/tmp
|
||||
bind /n/tmp /
|
||||
unmount /n/tmp
|
||||
} >[2] /dev/null
|
||||
|
||||
# start network
|
||||
if(grep -s WaveLAN/IEEE /dev/pcm0ctl){
|
||||
if (~ $debug 1) echo 'configure #l0 wavelan'
|
||||
echo -n 'configure #l0 wavelan'>/dev/pcm0ctl
|
||||
bind -a '#l0' /net
|
||||
switch($wvkey1){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'key1 '^$wvkey1 >/net/ether0/clone
|
||||
}
|
||||
switch($wvkey2){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'key2 '^$wvkey2 >/net/ether0/clone
|
||||
}
|
||||
switch($wvkey3){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'key3 '^$wvkey3 >/net/ether0/clone
|
||||
}
|
||||
switch($wvtxkey){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'txkey '^$wvtxkey >/net/ether0/clone
|
||||
}
|
||||
switch($wvmode){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'mode '^$wvmode >/net/ether0/clone
|
||||
}
|
||||
switch($wvibss){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'ibss '^$wvibss >/net/ether0/clone
|
||||
}
|
||||
switch($wvessid){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'essid '^$wvessid >/net/ether0/clone
|
||||
}
|
||||
switch($wvcrypt){
|
||||
case ''
|
||||
;
|
||||
case *
|
||||
echo -n 'crypt '^$wvcrypt >/net/ether0/clone
|
||||
}
|
||||
if (~ $debug 1) echo ip/ipconfig ether /net/ether0 $ipaddr $ipmask
|
||||
ip/ipconfig ether /net/ether0 $ipaddr $ipmask
|
||||
if(test -e /env/auth)
|
||||
echo ' auth='^$auth >>/net/ndb
|
||||
if(test -e /env/dns)
|
||||
echo ' dns='^$dns >>/net/ndb
|
||||
if(test -e /env/dnsdomain)
|
||||
echo ' dnsdomain='^$dnsdomain >>/net/ndb
|
||||
if(test -e /env/authdom)
|
||||
echo ' authdom='^$authdom >>/net/ndb
|
||||
|
||||
if (~ $debug 1) echo ndb/cs
|
||||
ndb/cs
|
||||
ndb/dns -r
|
||||
}
|
||||
|
||||
auth/factotum -n -s factotum -a $auth
|
||||
|
||||
if(! test -e /env/font)
|
||||
font=/lib/font/bit/lucidasans/unicode.6.font
|
||||
if(! test -e /env/tabstop)
|
||||
tabstop=2
|
||||
|
||||
if (test -d /usr/$user) {
|
||||
home=/usr/$user
|
||||
cd $home
|
||||
if (test -r lib/profile) {
|
||||
. lib/profile
|
||||
exec /bin/rc
|
||||
}
|
||||
if (test -r lib/windows) {
|
||||
if (~ $debug 1) echo 'exec rio -sk ''/bin/keyboard -l'' -i '$home'/lib/windows'
|
||||
exec rio -sk '/bin/keyboard -l -w' -i $home/lib/windows
|
||||
}
|
||||
}
|
||||
# bind in read/write file system
|
||||
if (~ $debug 1) echo 'exec rio -sk ''/bin/keyboard -l'''
|
||||
exec rio -sk '/bin/keyboard -l -w'
|
|
@ -1,6 +0,0 @@
|
|||
#
|
||||
# files comprising the database
|
||||
#
|
||||
database=
|
||||
file=/lib/ndb/local
|
||||
file=/lib/ndb/common
|
|
@ -1,41 +0,0 @@
|
|||
#!/bin/rc
|
||||
|
||||
# $proxy is typically set to tailfan's address.
|
||||
ipnet=`{grep 'ip=' /net/ndb | sed 's/^.*ip=([0-9]+\.[0-9]+\.[0-9]+\.).*$/\1/'}
|
||||
if (~ $proxy $ipnet^*){
|
||||
# Use a proxy
|
||||
echo import $proxy /net /net
|
||||
import $proxy /net /net
|
||||
}
|
||||
|
||||
switch($fs){
|
||||
case ''
|
||||
echo you must set the environment variable fs
|
||||
exit 0
|
||||
}
|
||||
if (! test -e /mnt/factotum) {
|
||||
if (test -e /srv/factotum) {
|
||||
mount -b /srv/factotum /mnt
|
||||
}
|
||||
if not {
|
||||
auth/factotum -u
|
||||
}
|
||||
}
|
||||
srv -m $fs $fs /n/fs
|
||||
bind -b /n/fs/arm/bin /bin
|
||||
bind -b /n/fs/rc/bin /bin
|
||||
bind -a /n/fs/lib /lib
|
||||
bind -b /n/fs/sys /sys
|
||||
bind -a /n/fs/usr /usr
|
||||
bind -c /n/fs/mail /mail
|
||||
bind -c /n/fs/acme /acme
|
||||
user=`{cat /dev/user}
|
||||
home=/usr/$user
|
||||
bind -a /n/fs/usr/$user /usr/$user
|
||||
bind -cb /usr/$user/tmp /tmp
|
||||
bind -b /usr/$user/bin/rc /bin
|
||||
bind -b /usr/$user/bin/arm /bin
|
||||
bind -a /n/fs/lib/font/bit/lucidasans /lib/font/bit/lucidasans
|
||||
bind -a /n/fs/lib/font/bit/lucida /lib/font/bit/lucida
|
||||
bind -a /n/fs/lib/font/bit/misc /lib/font/bit/misc
|
||||
#service=cpu aux/listen -t /bin/service
|
|
@ -1,53 +0,0 @@
|
|||
# root
|
||||
mount #s/boot /root
|
||||
bind -a /root /
|
||||
bind -c /root/mnt /mnt
|
||||
|
||||
# kernel devices
|
||||
bind #c /dev
|
||||
bind #d /fd
|
||||
bind -c #e /env
|
||||
bind #p /proc
|
||||
bind -c #s /srv
|
||||
bind -a #t /dev
|
||||
bind -a #r /dev
|
||||
bind -a #m /dev
|
||||
bind -a #y /dev
|
||||
bind -a #I /net
|
||||
bind -a #A /dev
|
||||
bind -a #F /dev
|
||||
bind -a #¤ /dev
|
||||
|
||||
# servers
|
||||
mount -a /srv/cs /net
|
||||
mount -a /srv/dns /net
|
||||
mount -a /srv/factotum /mnt
|
||||
|
||||
# read/write file system
|
||||
mount /srv/brzr /n/brzr
|
||||
mount /srv/brzr /n/tmp
|
||||
bind -a /n /n/tmp/n
|
||||
bind -a /sys/lib /n/tmp/sys/lib
|
||||
bind -a /sys /n/tmp/sys
|
||||
bind -a /arm/bin/auth /n/tmp/arm/bin/auth
|
||||
bind -a /arm/bin/ndb /n/tmp/arm/bin/ndb
|
||||
bind -a /arm/bin/ip /n/tmp/arm/bin/ip
|
||||
bind -a /arm/bin/aux /n/tmp/arm/bin/aux
|
||||
bind -a /arm/bin /n/tmp/arm/bin
|
||||
bind -a /arm /n/tmp/arm
|
||||
bind -a /lib/ndb /n/tmp/lib/ndb
|
||||
bind -a /lib/font /n/tmp/lib/font
|
||||
bind -a /lib /n/tmp/lib
|
||||
bind -a / /n/tmp
|
||||
bind /n/tmp /
|
||||
unmount /n/tmp
|
||||
|
||||
# standard bin
|
||||
bind /arm/bin /bin
|
||||
bind -a /rc/bin /bin
|
||||
bind -a /arm/bin/bitsy /bin
|
||||
|
||||
# user defines
|
||||
bind -cb /usr/$user/tmp /tmp
|
||||
bind -b /usr/$user/bin/rc /bin
|
||||
bind -b /usr/$user/bin/arm /bin
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/rc
|
||||
if(grep -s WaveLAN/IEEE /dev/pcm0ctl){
|
||||
echo -n 'configure #l0 WaveLAN/IEEE'>/dev/pcm0ctl
|
||||
bind -a '#l0' /net
|
||||
echo -n 'key moon1'>/net/ether0/clone
|
||||
ip/ipconfig ether /net/ether0
|
||||
ndb/cs
|
||||
ndb/dns -r
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
11 9
|
||||
0x0000 0x00FF lsr.10
|
||||
0x0100 0x01f0 ../lucida/EuroLatin.5.0
|
||||
0x2000 0x20aa ../lucida/GenPunct.5.0
|
||||
0x2200 0x22f1 ../lucida/MathOps1.5.0
|
|
@ -1,358 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "pool.h"
|
||||
|
||||
/* Power management for the bitsy */
|
||||
|
||||
#define TODFREQ 1000000000LL
|
||||
|
||||
/* saved state during power down.
|
||||
* it's only used up to 164/4.
|
||||
* it's only used by routines in l.s
|
||||
*/
|
||||
ulong power_state[200/4];
|
||||
|
||||
ulong resumeaddr[1];
|
||||
Rendez powerr;
|
||||
ulong powerflag = 0; /* set to start power-off sequence */
|
||||
|
||||
extern void power_resume(void);
|
||||
extern int setpowerlabel(void);
|
||||
extern void _start(void);
|
||||
extern Uart sa1110uart[];
|
||||
|
||||
GPIOregs savedgpioregs;
|
||||
Intrregs savedintrregs;
|
||||
|
||||
#define R(p) ((Uartregs*)((p)->regs))
|
||||
|
||||
uchar *savedtext;
|
||||
|
||||
static void
|
||||
checkflash(void)
|
||||
{
|
||||
ulong *p;
|
||||
ulong s;
|
||||
|
||||
s = 0;
|
||||
for (p = (ulong*)FLASHZERO; p < (ulong*)(FLASHZERO+8*1024*1024); p++)
|
||||
s += *p;
|
||||
iprint("flash checksum is 0x%lux\n", s);
|
||||
}
|
||||
|
||||
static void
|
||||
checkktext(void)
|
||||
{
|
||||
ulong *p;
|
||||
ulong s;
|
||||
|
||||
s = 0;
|
||||
for (p = (ulong*)_start; p < (ulong*)etext; p++){
|
||||
if(*p == 0)
|
||||
iprint("%#p->0\n", p);
|
||||
if (((ulong)p & 0x1fff) == 0){
|
||||
iprint("page 0x%lux checksum 0x%lux\n",
|
||||
(ulong)(p-1)&~0x1fff, s);
|
||||
s = 0;
|
||||
}
|
||||
s += *p;
|
||||
}
|
||||
iprint("page 0x%lux checksum 0x%lux\n", (ulong)(p-1)&~0x1fff, s);
|
||||
}
|
||||
|
||||
static void
|
||||
checkpagetab(void)
|
||||
{
|
||||
extern ulong l1table;
|
||||
ulong *p;
|
||||
ulong s;
|
||||
|
||||
s = 0;
|
||||
for (p = (ulong*)l1table; p < (ulong*)(l1table+16*1024); p++)
|
||||
s += *p;
|
||||
iprint("page table checksum is 0x%lux\n", s);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dumpitall(void)
|
||||
{
|
||||
extern ulong l1table;
|
||||
|
||||
iprint("intr: icip %lux iclr %lux iccr %lux icmr %lux\n",
|
||||
intrregs->icip,
|
||||
intrregs->iclr, intrregs->iccr, intrregs->icmr );
|
||||
iprint("gpio: lvl %lux dir %lux, re %lux, fe %lux sts %lux alt %lux\n",
|
||||
gpioregs->level,
|
||||
gpioregs->direction, gpioregs->rising, gpioregs->falling,
|
||||
gpioregs->edgestatus, gpioregs->altfunc);
|
||||
iprint("uart1: %lux %lux %lux \nuart3: %lux %lux %lux\n",
|
||||
R(&sa1110uart[0])->ctl[0], R(&sa1110uart[0])->status[0], R(&sa1110uart[0])->status[1],
|
||||
R(&sa1110uart[1])->ctl[0], R(&sa1110uart[1])->status[0], R(&sa1110uart[1])->status[1]);
|
||||
iprint("tmr: osmr %lux %lux %lux %lux oscr %lux ossr %lux oier %lux\n",
|
||||
timerregs->osmr[0], timerregs->osmr[1],
|
||||
timerregs->osmr[2], timerregs->osmr[3],
|
||||
timerregs->oscr, timerregs->ossr, timerregs->oier);
|
||||
iprint("dram: mdcnfg %lux mdrefr %lux cas %lux %lux %lux %lux %lux %lux\n",
|
||||
memconfregs->mdcnfg, memconfregs->mdrefr,
|
||||
memconfregs->mdcas00, memconfregs->mdcas01,memconfregs->mdcas02,
|
||||
memconfregs->mdcas20, memconfregs->mdcas21,memconfregs->mdcas22);
|
||||
iprint("dram: mdcnfg msc %lux %lux %lux mecr %lux\n",
|
||||
memconfregs->msc0, memconfregs->msc1,memconfregs->msc2,
|
||||
memconfregs->mecr);
|
||||
iprint("mmu: CpControl %lux CpTTB %lux CpDAC %lux l1table 0x%lux\n",
|
||||
getcontrol(), getttb(), getdac(), l1table);
|
||||
iprint("powerregs: pmcr %lux pssr %lux pcfr %lux ppcr %lux pwer %lux pspr %lux pgsr %lux posr %lux\n",
|
||||
powerregs->pmcr, powerregs->pssr, powerregs->pcfr, powerregs->ppcr,
|
||||
powerregs->pwer, powerregs->pspr, powerregs->pgsr, powerregs->posr);
|
||||
checkpagetab();
|
||||
checkflash();
|
||||
checkktext();
|
||||
iprint("\n\n");
|
||||
}
|
||||
|
||||
static void
|
||||
intrcpy(Intrregs *to, Intrregs *from)
|
||||
{
|
||||
to->iclr = from->iclr;
|
||||
to->iccr = from->iccr;
|
||||
to->icmr = from->icmr; // interrupts enabled
|
||||
}
|
||||
|
||||
static void
|
||||
gpiosave(GPIOregs *to, GPIOregs *from)
|
||||
{
|
||||
to->level = from->level;
|
||||
to->rising = from->rising; // gpio intrs enabled
|
||||
to->falling= from->falling; // gpio intrs enabled
|
||||
to->altfunc = from->altfunc;
|
||||
to->direction = from->direction;
|
||||
}
|
||||
|
||||
static void
|
||||
gpiorestore(GPIOregs *to, GPIOregs *from)
|
||||
{
|
||||
to->direction = from->direction;
|
||||
to->altfunc = from->altfunc;
|
||||
to->set = from->level & 0x0fffffff;
|
||||
to->clear = ~from->level & 0x0fffffff;
|
||||
to->rising = from->rising; // gpio intrs enabled
|
||||
to->falling= from->falling; // gpio intrs enabled
|
||||
}
|
||||
|
||||
void (*restart)(void) = nil;
|
||||
|
||||
static int
|
||||
bitno(ulong x)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8*sizeof(x); i++)
|
||||
if((1<<i) & x)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
powerdown(void *)
|
||||
{
|
||||
return powerflag;
|
||||
}
|
||||
|
||||
void
|
||||
deepsleep(void) {
|
||||
static int power_pl;
|
||||
ulong xsp, xlink;
|
||||
// ulong mecr;
|
||||
ulong clkd;
|
||||
vlong savedtod;
|
||||
extern void power_resume(void);
|
||||
|
||||
power_pl = splhi();
|
||||
xlink = getcallerpc(&xlink);
|
||||
|
||||
/* Power down */
|
||||
pcmciapower(0);
|
||||
irpower(0);
|
||||
audiopower(0);
|
||||
screenpower(0);
|
||||
µcpower(0);
|
||||
iprint("entering suspend mode, sp = %#p, pc = 0x%lux, psw = 0x%ux\n",
|
||||
&xsp, xlink, power_pl);
|
||||
// dumpitall();
|
||||
delay(1000);
|
||||
uartpower(0);
|
||||
rs232power(0);
|
||||
clockpower(0);
|
||||
gpiosave(&savedgpioregs, gpioregs);
|
||||
intrcpy(&savedintrregs, intrregs);
|
||||
cacheflush();
|
||||
delay(50);
|
||||
if(setpowerlabel()){
|
||||
/* return here with mmu back on */
|
||||
trapresume();
|
||||
|
||||
gpiorestore(gpioregs, &savedgpioregs);
|
||||
delay(50);
|
||||
intrcpy(intrregs, &savedintrregs);
|
||||
if(intrregs->icip & (1<<IRQgpio0)){
|
||||
// don't want to sleep now. clear on/off irq.
|
||||
gpioregs->edgestatus = (1<<IRQgpio0);
|
||||
intrregs->icip = (1<<IRQgpio0);
|
||||
}
|
||||
clkd = clockpower(1);
|
||||
gpclkregs->r0 = 1<<0;
|
||||
todset(savedtod + clkd * TODFREQ, 0LL, 0);
|
||||
resetsuspendtimer();
|
||||
rs232power(1);
|
||||
uartpower(1);
|
||||
delay(100);
|
||||
xlink = getcallerpc(&xlink);
|
||||
iprint("\nresuming execution, sp = %#p, pc = 0x%lux, psw = 0x%ux\n",
|
||||
&xsp, xlink, splhi());
|
||||
// dumpitall();
|
||||
delay(1000);
|
||||
// irpower(1);
|
||||
audiopower(1);
|
||||
µcpower(1);
|
||||
screenpower(1);
|
||||
pcmciapower(1);
|
||||
splx(power_pl);
|
||||
return;
|
||||
}
|
||||
cacheflush();
|
||||
delay(100);
|
||||
savedtod = todget(nil);
|
||||
power_down();
|
||||
/* no return */
|
||||
}
|
||||
|
||||
void
|
||||
powerkproc(void*)
|
||||
{
|
||||
ulong xlink, xlink1;
|
||||
|
||||
while(waserror())
|
||||
;
|
||||
|
||||
for(;;){
|
||||
while(powerflag == 0)
|
||||
sleep(&powerr, powerdown, 0);
|
||||
|
||||
xlink = getcallerpc(&xlink);
|
||||
|
||||
// iprint("call deepsleep, pc = 0x%lux, sp = 0x%lux\n", xlink, &xlink);
|
||||
deepsleep();
|
||||
xlink1 = getcallerpc(&xlink1);
|
||||
|
||||
delay(2000);
|
||||
|
||||
// iprint("deepsleep returned, pc = 0x%lux, sp = 0x%lux\n", xlink1, &xlink);
|
||||
powerflag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
onoffintr(Ureg* , void*)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Power down interrupt comes on power button release.
|
||||
* Act only after button has been released a full 100 ms
|
||||
*/
|
||||
|
||||
if (powerflag)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
delay(1);
|
||||
if ((gpioregs->level & GPIO_PWR_ON_i) == 0)
|
||||
return; /* bounced */
|
||||
}
|
||||
|
||||
powerflag = 1;
|
||||
wakeup(&powerr);
|
||||
}
|
||||
|
||||
static void
|
||||
blanktimer(void)
|
||||
{
|
||||
drawactive(0);
|
||||
}
|
||||
|
||||
static ulong suspendtime = 120 * HZ;
|
||||
static int lastsuspend;
|
||||
|
||||
void
|
||||
resetsuspendtimer(void)
|
||||
{
|
||||
suspendtime = 60 * HZ;
|
||||
}
|
||||
|
||||
static void
|
||||
suspendtimer(void)
|
||||
{
|
||||
#ifdef notdef
|
||||
uvlong now;
|
||||
|
||||
if (suspendtime > 0)
|
||||
suspendtime--;
|
||||
if (suspendtime == 0){
|
||||
now = seconds();
|
||||
if (now < lastsuspend + 10){
|
||||
resetsuspendtimer();
|
||||
return;
|
||||
}
|
||||
lastsuspend = seconds();
|
||||
deepsleep();
|
||||
lastsuspend = seconds();
|
||||
return;
|
||||
}
|
||||
#endif /* notdef */
|
||||
}
|
||||
|
||||
void
|
||||
powerinit(void)
|
||||
{
|
||||
extern ulong power_magic;
|
||||
extern ulong power_code;
|
||||
extern ulong doze_code;
|
||||
ulong *p, *q, i;
|
||||
|
||||
p = (ulong*)(((ulong)&power_magic + 0x1f) & ~0x1f);
|
||||
q = &power_code;
|
||||
for (i = 0; i < 8; i++)
|
||||
*p++ = *q++;
|
||||
p = (ulong*)(((ulong)doze + 0x3f) & ~0x1f);
|
||||
q = &doze_code;
|
||||
for (i = 0; i < 3; i++)
|
||||
*p++ = *q++;
|
||||
|
||||
*resumeaddr = (ulong) power_resume;
|
||||
addclock0link(blanktimer, 1000/HZ);
|
||||
addclock0link(suspendtimer, 1000/HZ);
|
||||
intrenable(GPIOrising, bitno(GPIO_PWR_ON_i), onoffintr, nil, "on/off");
|
||||
}
|
||||
|
||||
void
|
||||
idlehands(void)
|
||||
{
|
||||
char *msgb = "idlehands called with splhi\n";
|
||||
char *msga = "doze returns with splhi\n";
|
||||
|
||||
if(!islo()){
|
||||
uartputs(msga, strlen(msga));
|
||||
spllo();
|
||||
}
|
||||
doze();
|
||||
if(!islo()){
|
||||
uartputs(msgb, strlen(msgb));
|
||||
spllo();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/error.h"
|
||||
#include "sa1110dma.h"
|
||||
|
||||
static int debug = 0;
|
||||
|
||||
/*
|
||||
* DMA helper routines
|
||||
*/
|
||||
|
||||
enum {
|
||||
NDMA = 6, /* Number of DMA channels */
|
||||
DMAREGS = 0xb0000000, /* DMA registers, physical */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* Device Address Register, DDAR */
|
||||
RW = 0,
|
||||
E = 1,
|
||||
BS = 2,
|
||||
DW = 3,
|
||||
DS = 4, /* bits 4 - 7 */
|
||||
DA = 8 /* bits 8 - 31 */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* Device Control & Status Register, DCSR */
|
||||
RUN = 0,
|
||||
IE = 1,
|
||||
ERROR = 2,
|
||||
DONEA = 3,
|
||||
STRTA = 4,
|
||||
DONEB = 5,
|
||||
STRTB = 6,
|
||||
BIU = 7
|
||||
};
|
||||
|
||||
typedef struct DMAchan {
|
||||
int allocated;
|
||||
Rendez r;
|
||||
void (*intr)(void*, ulong);
|
||||
void *param;
|
||||
} DMAchan;
|
||||
|
||||
struct {
|
||||
Lock;
|
||||
DMAchan chan[6];
|
||||
} dma;
|
||||
|
||||
struct dmaregs {
|
||||
ulong ddar;
|
||||
ulong dcsr_set;
|
||||
ulong dcsr_clr;
|
||||
ulong dcsr_rd;
|
||||
ulong dstrtA;
|
||||
ulong dxcntA;
|
||||
ulong dstrtB;
|
||||
ulong dxcntB;
|
||||
} *dmaregs;
|
||||
|
||||
static void dmaintr(Ureg*, void *);
|
||||
|
||||
void
|
||||
dmainit(void) {
|
||||
int i;
|
||||
|
||||
/* map the lcd regs into the kernel's virtual space */
|
||||
dmaregs = (struct dmaregs*)mapspecial(DMAREGS, NDMA*sizeof(struct dmaregs));
|
||||
if (debug) print("dma: dmaalloc registers 0x%ux mapped at 0x%p\n",
|
||||
DMAREGS, dmaregs);
|
||||
for (i = 0; i < NDMA; i++) {
|
||||
intrenable(IRQ, IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dmareset(int i, int rd, int bigendian, int burstsize, int datumsize, int device, ulong port) {
|
||||
ulong ddar;
|
||||
|
||||
ddar =
|
||||
(rd?1:0)<<RW |
|
||||
(bigendian?1:0)<<E |
|
||||
((burstsize==8)?1:0)<<BS |
|
||||
((datumsize==2)?1:0)<<DW |
|
||||
device<<DS |
|
||||
0x80000000 | ((ulong)port << 6);
|
||||
dmaregs[i].ddar = ddar;
|
||||
dmaregs[i].dcsr_clr = 0xff;
|
||||
if (debug) print("dma: dmareset: 0x%lux\n", ddar);
|
||||
}
|
||||
|
||||
int
|
||||
dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, ulong port, void (*intr)(void*, ulong), void *param) {
|
||||
int i;
|
||||
|
||||
lock(&dma);
|
||||
for (i = 0; i < NDMA; i++) {
|
||||
if (dma.chan[i].allocated)
|
||||
continue;
|
||||
dma.chan[i].allocated++;
|
||||
unlock(&dma);
|
||||
dmareset(i, rd, bigendian, burstsize, datumsize, device, port);
|
||||
dma.chan[i].intr = intr;
|
||||
dma.chan[i].param = param;
|
||||
return i;
|
||||
}
|
||||
unlock(&dma);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
dmafree(int i) {
|
||||
dmaregs[i].dcsr_clr = 0xff;
|
||||
dmaregs[i].ddar = 0;
|
||||
dma.chan[i].allocated = 0;
|
||||
dma.chan[i].intr = nil;
|
||||
}
|
||||
|
||||
void
|
||||
dmastop(int i) {
|
||||
dmaregs[i].dcsr_clr = 0xff;
|
||||
}
|
||||
|
||||
ulong
|
||||
dmastart(int chan, ulong addr, int count) {
|
||||
ulong status, n;
|
||||
static int last;
|
||||
|
||||
/* If this gets called from interrupt routines, make sure ilocks are used */
|
||||
status = dmaregs[chan].dcsr_rd;
|
||||
if (debug > 1)
|
||||
iprint("dma: dmastart 0x%lux\n", status);
|
||||
|
||||
if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
|
||||
return 0;
|
||||
}
|
||||
cachewbregion(addr, count);
|
||||
n = 0x100;
|
||||
if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
|
||||
(status & (1<<BIU | 1<<STRTA)) == 0) {
|
||||
if (status & 1<<STRTA)
|
||||
iprint("writing busy dma entry 0x%lux\n", status);
|
||||
if (status & 1<<STRTB)
|
||||
n = (last == 1)?0x200:0x300;
|
||||
last = 2;
|
||||
dmaregs[chan].dstrtA = addr;
|
||||
dmaregs[chan].dxcntA = count;
|
||||
dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
|
||||
n |= 1<<DONEA;
|
||||
} else {
|
||||
if (status & 1<<STRTB)
|
||||
iprint("writing busy dma entry 0x%lux\n", status);
|
||||
if (status & 1<<STRTA)
|
||||
n = (last == 2)?0x200:0x300;
|
||||
last = 1;
|
||||
dmaregs[chan].dstrtB = addr;
|
||||
dmaregs[chan].dxcntB = count;
|
||||
dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
|
||||
n |= 1<<DONEB;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
dmaidle(int chan) {
|
||||
ulong status;
|
||||
|
||||
status = dmaregs[chan].dcsr_rd;
|
||||
if (debug > 1) print("dmaidle: 0x%lux\n", status);
|
||||
return (status & (1<<STRTA|1<<STRTB)) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_dmaidle(void* chan) {
|
||||
ulong status;
|
||||
|
||||
status = dmaregs[(int)chan].dcsr_rd;
|
||||
return (status & (1<<STRTA|1<<STRTB)) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
dmawait(int chan) {
|
||||
while (!dmaidle(chan))
|
||||
sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
|
||||
}
|
||||
|
||||
/*
|
||||
* interrupt routine
|
||||
*/
|
||||
static void
|
||||
dmaintr(Ureg*, void *x)
|
||||
{
|
||||
int i;
|
||||
struct dmaregs *regs = x;
|
||||
ulong dcsr, donebit;
|
||||
|
||||
i = regs - dmaregs;
|
||||
dcsr = regs->dcsr_rd;
|
||||
if (debug > 1)
|
||||
iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);
|
||||
if (dcsr & 1<<ERROR)
|
||||
iprint("error, channel %d, status 0x%lux\n", i, dcsr);
|
||||
donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
|
||||
if (dcsr & donebit) {
|
||||
regs->dcsr_clr = 1<<DONEA|1<<DONEB;
|
||||
if (dma.chan[i].intr) {
|
||||
(*dma.chan[i].intr)(dma.chan[i].param, dcsr & (1<<DONEA|1<<DONEB));
|
||||
}
|
||||
wakeup(&dma.chan[i].r);
|
||||
return;
|
||||
}
|
||||
if (dcsr & 1<<ERROR) {
|
||||
regs->dcsr_clr = ERROR;
|
||||
iprint("DMA error, channel %d, status 0x%lux\n", i, dcsr);
|
||||
if (dma.chan[i].intr) {
|
||||
(*dma.chan[i].intr)(dma.chan[i].param, 0);
|
||||
}
|
||||
wakeup(&dma.chan[i].r);
|
||||
return;
|
||||
}
|
||||
iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
enum {
|
||||
Port4MCP = 0x80060008,
|
||||
Port4SSP = 0x8007006c,
|
||||
AudioDMA = 0xa,
|
||||
SSPXmitDMA = 0xe,
|
||||
SSPRecvDMA = 0xf,
|
||||
};
|
||||
|
||||
void dmainit(void);
|
||||
int dmaalloc(int, int, int, int, int, ulong, void (*)(void*, ulong), void*);
|
||||
void dmareset(int, int, int, int, int, int, ulong);
|
||||
void dmafree(int);
|
||||
|
||||
ulong dmastart(int, ulong, int);
|
||||
|
||||
void dmawait(int);
|
||||
void dmastop(int);
|
||||
int dmaidle(int);
|
|
@ -1,492 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
#include "gamma.h"
|
||||
|
||||
#define MINX 8
|
||||
|
||||
int landscape = 0; /* orientation of the screen, default is 0: portait */
|
||||
|
||||
enum {
|
||||
Wid = 240,
|
||||
Ht = 320,
|
||||
Pal0 = 0x2000, /* 16-bit pixel data in active mode (12 in passive) */
|
||||
|
||||
hsw = 0x00,
|
||||
elw = 0x0e,
|
||||
blw = 0x0d,
|
||||
|
||||
vsw = 0x02,
|
||||
efw = 0x01,
|
||||
bfw = 0x0a,
|
||||
|
||||
pcd = 0x10,
|
||||
};
|
||||
|
||||
struct sa1110fb {
|
||||
/* Frame buffer for 16-bit active color */
|
||||
short palette[16]; /* entry 0 set to Pal0, the rest to 0 */
|
||||
ushort pixel[Wid*Ht]; /* Pixel data */
|
||||
} *framebuf;
|
||||
|
||||
enum {
|
||||
/* LCD Control Register 0, lcd->lccr0 */
|
||||
LEN = 0, /* 1 bit */
|
||||
CMS = 1, /* 1 bit */
|
||||
SDS = 2, /* 1 bit */
|
||||
LDM = 3, /* 1 bit */
|
||||
BAM = 4, /* 1 bit */
|
||||
ERM = 5, /* 1 bit */
|
||||
PAS = 7, /* 1 bit */
|
||||
BLE = 8, /* 1 bit */
|
||||
DPD = 9, /* 1 bit */
|
||||
PDD = 12, /* 8 bits */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* LCD Control Register 1, lcd->lccr1 */
|
||||
PPL = 0, /* 10 bits */
|
||||
HSW = 10, /* 6 bits */
|
||||
ELW = 16, /* 8 bits */
|
||||
BLW = 24, /* 8 bits */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* LCD Control Register 2, lcd->lccr2 */
|
||||
LPP = 0, /* 10 bits */
|
||||
VSW = 10, /* 6 bits */
|
||||
EFW = 16, /* 8 bits */
|
||||
BFW = 24, /* 8 bits */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* LCD Control Register 3, lcd->lccr3 */
|
||||
PCD = 0, /* 8 bits */
|
||||
ACB = 8, /* 8 bits */
|
||||
API = 16, /* 4 bits */
|
||||
VSP = 20, /* 1 bit */
|
||||
HSP = 21, /* 1 bit */
|
||||
PCP = 22, /* 1 bit */
|
||||
OEP = 23, /* 1 bit */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* LCD Status Register, lcd->lcsr */
|
||||
LDD = 0, /* 1 bit */
|
||||
BAU = 1, /* 1 bit */
|
||||
BER = 2, /* 1 bit */
|
||||
ABC = 3, /* 1 bit */
|
||||
IOL = 4, /* 1 bit */
|
||||
IUL = 5, /* 1 bit */
|
||||
OIU = 6, /* 1 bit */
|
||||
IUU = 7, /* 1 bit */
|
||||
OOL = 8, /* 1 bit */
|
||||
OUL = 9, /* 1 bit */
|
||||
OOU = 10, /* 1 bit */
|
||||
OUU = 11, /* 1 bit */
|
||||
};
|
||||
|
||||
struct sa1110regs {
|
||||
ulong lccr0;
|
||||
ulong lcsr;
|
||||
ulong dummies[2];
|
||||
short* dbar1;
|
||||
ulong dcar1;
|
||||
ulong dbar2;
|
||||
ulong dcar2;
|
||||
ulong lccr1;
|
||||
ulong lccr2;
|
||||
ulong lccr3;
|
||||
} *lcd;
|
||||
|
||||
static Memdata xgdata;
|
||||
|
||||
static Memimage xgscreen =
|
||||
{
|
||||
{ 0, 0, Wid, Ht }, /* r */
|
||||
{ 0, 0, Wid, Ht }, /* clipr */
|
||||
16, /* depth */
|
||||
3, /* nchan */
|
||||
RGB16, /* chan */
|
||||
nil, /* cmap */
|
||||
&xgdata, /* data */
|
||||
0, /* zero */
|
||||
Wid/2, /* width */
|
||||
0, /* layer */
|
||||
0, /* flags */
|
||||
};
|
||||
|
||||
struct{
|
||||
Point pos;
|
||||
int bwid;
|
||||
}out;
|
||||
|
||||
Memimage *gscreen;
|
||||
Memimage *conscol;
|
||||
Memimage *back;
|
||||
|
||||
Memsubfont *memdefont;
|
||||
|
||||
Lock screenlock;
|
||||
|
||||
ushort *vscreen; /* virtual screen */
|
||||
Rectangle window;
|
||||
Point curpos;
|
||||
int h, w;
|
||||
|
||||
static ulong rep(ulong, int);
|
||||
static void screenwin(void);
|
||||
static void screenputc(char *buf);
|
||||
static void bitsyscreenputs(char *s, int n);
|
||||
static void scroll(void);
|
||||
|
||||
static void
|
||||
lcdinit(void)
|
||||
{
|
||||
/* the following line works because main memory is direct mapped */
|
||||
gpioregs->direction |=
|
||||
GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
|
||||
|GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o;
|
||||
gpioregs->altfunc |=
|
||||
GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
|
||||
|GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o;
|
||||
framebuf->palette[0] = Pal0;
|
||||
lcd->dbar1 = framebuf->palette;
|
||||
lcd->lccr3 = pcd<<PCD | 0<<ACB | 0<<API | 1<<VSP | 1<<HSP | 0<<PCP | 0<<OEP;
|
||||
lcd->lccr2 = (Wid-1)<<LPP | vsw<<VSW | efw<<EFW | bfw<<BFW;
|
||||
lcd->lccr1 = (Ht-16)<<PPL | hsw<<HSW | elw<<ELW | blw<<BLW;
|
||||
lcd->lccr0 = 1<<LEN | 0<<CMS | 0<<SDS | 1<<LDM | 1<<BAM | 1<<ERM | 1<<PAS | 0<<BLE | 0<<DPD | 0<<PDD;
|
||||
}
|
||||
|
||||
void
|
||||
flipscreen(int ls) {
|
||||
if (ls == landscape)
|
||||
return;
|
||||
if (ls) {
|
||||
gscreen->r = Rect(0, 0, Ht, Wid);
|
||||
gscreen->clipr = gscreen->r;
|
||||
gscreen->width = Ht/2;
|
||||
xgdata.bdata = (uchar *)framebuf->pixel;
|
||||
} else {
|
||||
gscreen->r = Rect(0, 0, Wid, Ht);
|
||||
gscreen->clipr = gscreen->r;
|
||||
gscreen->width = Wid/2;
|
||||
xgdata.bdata = (uchar *)vscreen;
|
||||
}
|
||||
landscape = ls;
|
||||
}
|
||||
|
||||
void
|
||||
lcdtweak(Cmdbuf *cmd)
|
||||
{
|
||||
if(cmd->nf < 4)
|
||||
return;
|
||||
if(*cmd->f[0] == 'h')
|
||||
lcd->lccr1 = ((Ht-16)<<PPL)
|
||||
| (strtol(cmd->f[1], 0, 0)<<HSW)
|
||||
| (strtol(cmd->f[2], 0, 0)<<ELW)
|
||||
| (strtol(cmd->f[3], 0, 0)<<BLW);
|
||||
if(*cmd->f[0] == 'v')
|
||||
lcd->lccr2 = ((Wid-1)<<LPP)
|
||||
| (strtol(cmd->f[1], 0, 0)<<VSW)
|
||||
| (strtol(cmd->f[2], 0, 0)<<EFW)
|
||||
| (strtol(cmd->f[3], 0, 0)<<BFW);
|
||||
}
|
||||
|
||||
void
|
||||
screenpower(int on)
|
||||
{
|
||||
blankscreen(on == 0);
|
||||
}
|
||||
|
||||
void
|
||||
screeninit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* map the lcd regs into the kernel's virtual space */
|
||||
lcd = (struct sa1110regs*)mapspecial(LCDREGS, sizeof(struct sa1110regs));;
|
||||
|
||||
framebuf = xspanalloc(sizeof *framebuf, 0x100, 0);
|
||||
|
||||
vscreen = xalloc(sizeof(ushort)*Wid*Ht);
|
||||
|
||||
lcdpower(1);
|
||||
lcdinit();
|
||||
|
||||
gscreen = &xgscreen;
|
||||
|
||||
xgdata.ref = 1;
|
||||
i = 0;
|
||||
if (landscape) {
|
||||
gscreen->r = Rect(0, 0, Ht, Wid);
|
||||
gscreen->clipr = gscreen->r;
|
||||
gscreen->width = Ht/2;
|
||||
xgdata.bdata = (uchar *)framebuf->pixel;
|
||||
while (i < Wid*Ht*1/3) framebuf->pixel[i++] = 0xf800; /* red */
|
||||
while (i < Wid*Ht*2/3) framebuf->pixel[i++] = 0xffff; /* white */
|
||||
while (i < Wid*Ht*3/3) framebuf->pixel[i++] = 0x001f; /* blue */
|
||||
} else {
|
||||
gscreen->r = Rect(0, 0, Wid, Ht);
|
||||
gscreen->clipr = gscreen->r;
|
||||
gscreen->width = Wid/2;
|
||||
xgdata.bdata = (uchar *)vscreen;
|
||||
while (i < Wid*Ht*1/3) vscreen[i++] = 0xf800; /* red */
|
||||
while (i < Wid*Ht*2/3) vscreen[i++] = 0xffff; /* white */
|
||||
while (i < Wid*Ht*3/3) vscreen[i++] = 0x001f; /* blue */
|
||||
flushmemscreen(gscreen->r);
|
||||
}
|
||||
memimageinit();
|
||||
memdefont = getmemdefont();
|
||||
|
||||
out.pos.x = MINX;
|
||||
out.pos.y = 0;
|
||||
out.bwid = memdefont->info[' '].width;
|
||||
|
||||
blanktime = 3; /* minutes */
|
||||
|
||||
screenwin();
|
||||
// screenputs = bitsyscreenputs;
|
||||
screenputs = nil;
|
||||
}
|
||||
|
||||
void
|
||||
flushmemscreen(Rectangle r)
|
||||
{
|
||||
int x, y;
|
||||
ulong start, end;
|
||||
|
||||
if (landscape == 0) {
|
||||
if (r.min.x < 0) r.min.x = 0;
|
||||
if (r.max.x > Wid) r.max.x = Wid;
|
||||
if (r.min.y < 0) r.min.y = 0;
|
||||
if (r.max.y > Ht) r.max.y = Ht;
|
||||
for (x = r.min.x; x < r.max.x; x++)
|
||||
for (y = r.min.y; y < r.max.y; y++)
|
||||
framebuf->pixel[(x+1)*Ht-1-y] = gamma[vscreen[y*Wid+x]];
|
||||
start = (ulong)&framebuf->pixel[(r.min.x+1)*Ht-1-(r.max.y-1)];
|
||||
end = (ulong)&framebuf->pixel[(r.max.x-1+1)*Ht-1-(r.min.y)];
|
||||
} else {
|
||||
start = (ulong)&framebuf->pixel[r.min.y*Ht + r.min.x];
|
||||
end = (ulong)&framebuf->pixel[(r.max.y-1)*Ht + r.max.x - 1];
|
||||
}
|
||||
cachewbregion(start, end-start);
|
||||
}
|
||||
|
||||
/*
|
||||
* export screen to devdraw
|
||||
*/
|
||||
uchar*
|
||||
attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
|
||||
{
|
||||
*r = gscreen->r;
|
||||
*d = gscreen->depth;
|
||||
*chan = gscreen->chan;
|
||||
*width = gscreen->width;
|
||||
*softscreen = (landscape == 0);
|
||||
|
||||
return (uchar*)gscreen->data->bdata;
|
||||
}
|
||||
|
||||
void
|
||||
getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
|
||||
{
|
||||
USED(p, pr, pg, pb);
|
||||
}
|
||||
|
||||
int
|
||||
setcolor(ulong p, ulong r, ulong g, ulong b)
|
||||
{
|
||||
USED(p,r,g,b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
blankscreen(int blank)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
if (blank) {
|
||||
lcd->lccr0 &= ~(1<<LEN); /* disable the LCD */
|
||||
cnt = 0;
|
||||
while((lcd->lcsr & (1<<LDD)) == 0) {
|
||||
delay(10);
|
||||
if (++cnt == 100) {
|
||||
iprint("LCD doesn't stop\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
lcdpower(0);
|
||||
} else {
|
||||
lcdpower(1);
|
||||
lcdinit();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bitsyscreenputs(char *s, int n)
|
||||
{
|
||||
int i;
|
||||
Rune r;
|
||||
char buf[4];
|
||||
|
||||
if(!islo()) {
|
||||
/* don't deadlock trying to print in interrupt */
|
||||
if(!canlock(&screenlock))
|
||||
return;
|
||||
}
|
||||
else
|
||||
lock(&screenlock);
|
||||
|
||||
while(n > 0){
|
||||
i = chartorune(&r, s);
|
||||
if(i == 0){
|
||||
s++;
|
||||
--n;
|
||||
continue;
|
||||
}
|
||||
memmove(buf, s, i);
|
||||
buf[i] = 0;
|
||||
n -= i;
|
||||
s += i;
|
||||
screenputc(buf);
|
||||
}
|
||||
unlock(&screenlock);
|
||||
}
|
||||
|
||||
static void
|
||||
screenwin(void)
|
||||
{
|
||||
Point p, q;
|
||||
char *greet;
|
||||
Memimage *orange;
|
||||
Rectangle r;
|
||||
|
||||
memsetchan(gscreen, RGB16);
|
||||
|
||||
back = memwhite;
|
||||
conscol = memblack;
|
||||
|
||||
orange = allocmemimage(Rect(0,0,1,1), RGB16);
|
||||
orange->flags |= Frepl;
|
||||
orange->clipr = gscreen->r;
|
||||
orange->data->bdata[0] = 0x40;
|
||||
orange->data->bdata[1] = 0xfd;
|
||||
|
||||
w = memdefont->info[' '].width;
|
||||
h = memdefont->height;
|
||||
|
||||
r = insetrect(gscreen->r, 4);
|
||||
|
||||
memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
|
||||
window = insetrect(r, 4);
|
||||
memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
|
||||
|
||||
memimagedraw(gscreen, Rect(window.min.x, window.min.y,
|
||||
window.max.x, window.min.y+h+5+6), orange, ZP, nil, ZP, S);
|
||||
freememimage(orange);
|
||||
window = insetrect(window, 5);
|
||||
|
||||
greet = " Plan 9 Console ";
|
||||
p = addpt(window.min, Pt(10, 0));
|
||||
q = memsubfontwidth(memdefont, greet);
|
||||
memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
|
||||
flushmemscreen(r);
|
||||
window.min.y += h+6;
|
||||
curpos = window.min;
|
||||
window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
|
||||
}
|
||||
|
||||
static void
|
||||
screenputc(char *buf)
|
||||
{
|
||||
Point p;
|
||||
int w, pos;
|
||||
Rectangle r;
|
||||
static int *xp;
|
||||
static int xbuf[256];
|
||||
|
||||
if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
|
||||
xp = xbuf;
|
||||
|
||||
switch(buf[0]) {
|
||||
case '\n':
|
||||
if(curpos.y+h >= window.max.y)
|
||||
scroll();
|
||||
curpos.y += h;
|
||||
screenputc("\r");
|
||||
break;
|
||||
case '\r':
|
||||
xp = xbuf;
|
||||
curpos.x = window.min.x;
|
||||
break;
|
||||
case '\t':
|
||||
p = memsubfontwidth(memdefont, " ");
|
||||
w = p.x;
|
||||
if(curpos.x >= window.max.x-4*w)
|
||||
screenputc("\n");
|
||||
|
||||
pos = (curpos.x-window.min.x)/w;
|
||||
pos = 4-(pos%4);
|
||||
*xp++ = curpos.x;
|
||||
r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
|
||||
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
|
||||
flushmemscreen(r);
|
||||
curpos.x += pos*w;
|
||||
break;
|
||||
case '\b':
|
||||
if(xp <= xbuf)
|
||||
break;
|
||||
xp--;
|
||||
r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
|
||||
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
|
||||
flushmemscreen(r);
|
||||
curpos.x = *xp;
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
p = memsubfontwidth(memdefont, buf);
|
||||
w = p.x;
|
||||
|
||||
if(curpos.x >= window.max.x-w)
|
||||
screenputc("\n");
|
||||
|
||||
*xp++ = curpos.x;
|
||||
r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
|
||||
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
|
||||
memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
|
||||
flushmemscreen(r);
|
||||
curpos.x += w;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
scroll(void)
|
||||
{
|
||||
int o;
|
||||
Point p;
|
||||
Rectangle r;
|
||||
|
||||
o = 8*h;
|
||||
r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
|
||||
p = Pt(window.min.x, window.min.y+o);
|
||||
memimagedraw(gscreen, r, gscreen, p, nil, p, S);
|
||||
flushmemscreen(r);
|
||||
r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
|
||||
memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
|
||||
flushmemscreen(r);
|
||||
|
||||
curpos.y -= o;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
typedef struct Cursorinfo Cursorinfo;
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
extern ulong blanktime;
|
||||
|
||||
struct Cursorinfo {
|
||||
Lock;
|
||||
};
|
||||
|
||||
extern void blankscreen(int);
|
||||
extern void flushmemscreen(Rectangle);
|
||||
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
|
||||
|
||||
#define ishwimage(i) 0
|
File diff suppressed because it is too large
Load diff
|
@ -1,81 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
typedef union Hblock Hblock;
|
||||
|
||||
#define TBLOCK 512
|
||||
#define NAMSIZ 100
|
||||
union Hblock
|
||||
{
|
||||
char dummy[TBLOCK];
|
||||
struct header
|
||||
{
|
||||
char name[NAMSIZ];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char chksum[8];
|
||||
char linkflag;
|
||||
char linkname[NAMSIZ];
|
||||
} dbuf;
|
||||
};
|
||||
|
||||
static int getdir(Hblock *hb, Dir *sp);
|
||||
static int checksum(Hblock *hb);
|
||||
|
||||
uchar*
|
||||
tarlookup(uchar *addr, char *file, int *dlen)
|
||||
{
|
||||
Hblock *hp;
|
||||
Dir dir;
|
||||
|
||||
hp = (Hblock*)addr;
|
||||
while(getdir(hp, &dir) != 0) {
|
||||
if(strcmp(file, hp->dbuf.name) == 0) {
|
||||
*dlen = dir.length;
|
||||
return (uchar*)(hp+1);
|
||||
}
|
||||
hp += (dir.length+TBLOCK-1)/TBLOCK + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
getdir(Hblock *hp, Dir *sp)
|
||||
{
|
||||
int chksum;
|
||||
|
||||
if (hp->dbuf.name[0] == '\0')
|
||||
return 0;
|
||||
sp->length = strtol(hp->dbuf.size, 0, 8);
|
||||
sp->mtime = strtol(hp->dbuf.mtime, 0, 8);
|
||||
chksum = strtol(hp->dbuf.chksum, 0, 8);
|
||||
if (chksum != checksum(hp)) {
|
||||
print("directory checksum error\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
checksum(Hblock *hp)
|
||||
{
|
||||
int i;
|
||||
char *cp;
|
||||
|
||||
i = 0;
|
||||
for (cp = hp->dummy; cp < &hp->dummy[TBLOCK]; cp++) {
|
||||
if(cp < hp->dbuf.chksum || cp >= &hp->dbuf.chksum[sizeof(hp->dbuf.chksum)])
|
||||
i += *cp & 0xff;
|
||||
else
|
||||
i += ' ' & 0xff;
|
||||
}
|
||||
return(i);
|
||||
}
|
|
@ -1,926 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "ureg.h"
|
||||
#include "../port/error.h"
|
||||
#include "tos.h"
|
||||
|
||||
Intrregs *intrregs;
|
||||
|
||||
typedef struct Vctl {
|
||||
Vctl* next; /* handlers on this vector */
|
||||
char *name; /* of driver, xallocated */
|
||||
void (*f)(Ureg*, void*); /* handler to call */
|
||||
void* a; /* argument to call it with */
|
||||
} Vctl;
|
||||
|
||||
static Lock vctllock;
|
||||
static Vctl *vctl[32];
|
||||
static Vctl *gpiovctl[27];
|
||||
static int gpioirqref[12];
|
||||
|
||||
/*
|
||||
* Layout at virtual address 0.
|
||||
*/
|
||||
typedef struct Vpage0 {
|
||||
void (*vectors[8])(void);
|
||||
ulong vtable[8];
|
||||
} Vpage0;
|
||||
Vpage0 *vpage0;
|
||||
|
||||
static int irq(Ureg*);
|
||||
static void gpiointr(Ureg*, void*);
|
||||
|
||||
/* recover state after power suspend
|
||||
* NB: to help debugging bad suspend code,
|
||||
* I changed some prints below to iprints,
|
||||
* to avoid deadlocks when a panic is being
|
||||
* issued during the suspend/resume handler.
|
||||
*/
|
||||
void
|
||||
trapresume(void)
|
||||
{
|
||||
vpage0 = (Vpage0*)EVECTORS;
|
||||
memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
|
||||
memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
|
||||
wbflush();
|
||||
mappedIvecEnable();
|
||||
}
|
||||
|
||||
/*
|
||||
* set up for exceptions
|
||||
*/
|
||||
void
|
||||
trapinit(void)
|
||||
{
|
||||
/* set up the exception vectors */
|
||||
vpage0 = (Vpage0*)EVECTORS;
|
||||
memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
|
||||
memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
|
||||
|
||||
wbflush();
|
||||
|
||||
/* use exception vectors at 0xFFFF0000 */
|
||||
mappedIvecEnable();
|
||||
|
||||
/* set up the stacks for the interrupt modes */
|
||||
setr13(PsrMfiq, m->sfiq);
|
||||
setr13(PsrMirq, m->sirq);
|
||||
setr13(PsrMabt, m->sabt);
|
||||
setr13(PsrMund, m->sund);
|
||||
|
||||
/* map in interrupt registers */
|
||||
intrregs = mapspecial(INTRREGS, sizeof(*intrregs));
|
||||
|
||||
/* make all interrupts IRQ (i.e. not FIQ) and disable all interrupts */
|
||||
intrregs->iclr = 0;
|
||||
intrregs->icmr = 0;
|
||||
|
||||
/* turn off all gpio interrupts */
|
||||
gpioregs->rising = 0;
|
||||
gpioregs->falling = 0;
|
||||
gpioregs->edgestatus = gpioregs->edgestatus;
|
||||
|
||||
/* allow all enabled interrupts to take processor out of sleep mode */
|
||||
intrregs->iccr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
trapdump(char *tag)
|
||||
{
|
||||
iprint("%s: icip %lux icmr %lux iclr %lux iccr %lux icfp %lux\n",
|
||||
tag, intrregs->icip, intrregs->icmr, intrregs->iclr,
|
||||
intrregs->iccr, intrregs->icfp);
|
||||
}
|
||||
|
||||
void
|
||||
warnregs(Ureg *ur, char *tag)
|
||||
{
|
||||
char buf[1024];
|
||||
char *e = buf+sizeof(buf);
|
||||
char *p;
|
||||
|
||||
p = seprint(buf, e, "%s:\n", tag);
|
||||
p = seprint(p, e, "type 0x%.8lux psr 0x%.8lux pc 0x%.8lux\n",
|
||||
ur->type, ur->psr, ur->pc);
|
||||
p = seprint(p, e, "r0 0x%.8lux r1 0x%.8lux r2 0x%.8lux r3 0x%.8lux\n",
|
||||
ur->r0, ur->r1, ur->r2, ur->r3);
|
||||
p = seprint(p, e, "r4 0x%.8lux r5 0x%.8lux r6 0x%.8lux r7 0x%.8lux\n",
|
||||
ur->r4, ur->r5, ur->r6, ur->r7);
|
||||
p = seprint(p, e, "r8 0x%.8lux r9 0x%.8lux r10 0x%.8lux r11 0x%.8lux\n",
|
||||
ur->r8, ur->r9, ur->r10, ur->r11);
|
||||
seprint(p, e, "r12 0x%.8lux r13 0x%.8lux r14 0x%.8lux\n",
|
||||
ur->r12, ur->r13, ur->r14);
|
||||
iprint("%s", buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* enable an irq interrupt
|
||||
*/
|
||||
static void
|
||||
irqenable(int irq, IntrHandler *f, void* a, char *name)
|
||||
{
|
||||
Vctl *v;
|
||||
|
||||
if(irq >= nelem(vctl) || irq < 0)
|
||||
panic("intrenable");
|
||||
|
||||
v = malloc(sizeof(Vctl));
|
||||
v->f = f;
|
||||
v->a = a;
|
||||
v->name = xalloc(strlen(name)+1);
|
||||
strcpy(v->name, name);
|
||||
|
||||
lock(&vctllock);
|
||||
v->next = vctl[irq];
|
||||
vctl[irq] = v;
|
||||
intrregs->icmr |= 1<<irq;
|
||||
unlock(&vctllock);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable an irq interrupt
|
||||
*/
|
||||
static void
|
||||
irqdisable(int irq, IntrHandler *f, void* a, char *name)
|
||||
{
|
||||
Vctl **vp, *v;
|
||||
|
||||
if(irq >= nelem(vctl) || irq < 0)
|
||||
panic("intrdisable");
|
||||
|
||||
lock(&vctllock);
|
||||
for(vp = &vctl[irq]; v = *vp; vp = &v->next)
|
||||
if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
|
||||
print("irqdisable: remove %s\n", name);
|
||||
*vp = v->next;
|
||||
free(v);
|
||||
break;
|
||||
}
|
||||
if (v == nil)
|
||||
print("irqdisable: irq %d, name %s not enabled\n", irq, name);
|
||||
if (vctl[irq] == nil){
|
||||
print("irqdisable: clear icmr bit %d\n", irq);
|
||||
intrregs->icmr &= ~(1<<irq);
|
||||
}
|
||||
unlock(&vctllock);
|
||||
}
|
||||
|
||||
/*
|
||||
* enable an interrupt
|
||||
*/
|
||||
void
|
||||
intrenable(int type, int which, IntrHandler *f, void* a, char *name)
|
||||
{
|
||||
int irq;
|
||||
Vctl *v;
|
||||
|
||||
if(type == IRQ){
|
||||
irqenable(which, f, a, name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* from here down, it must be a GPIO edge interrupt */
|
||||
irq = which;
|
||||
if(which >= nelem(gpiovctl) || which < 0)
|
||||
panic("intrenable");
|
||||
if(which > 11)
|
||||
irq = 11;
|
||||
|
||||
/* the pin had better be configured as input */
|
||||
if((1<<which) & gpioregs->direction)
|
||||
panic("intrenable of output pin %d", which);
|
||||
|
||||
/* create a second level vctl for the gpio edge interrupt */
|
||||
v = malloc(sizeof(Vctl));
|
||||
v->f = f;
|
||||
v->a = a;
|
||||
v->name = xalloc(strlen(name)+1);
|
||||
strcpy(v->name, name);
|
||||
|
||||
lock(&vctllock);
|
||||
v->next = gpiovctl[which];
|
||||
gpiovctl[which] = v;
|
||||
|
||||
/* set edge register to enable interrupt */
|
||||
switch(type){
|
||||
case GPIOboth:
|
||||
gpioregs->rising |= 1<<which;
|
||||
gpioregs->falling |= 1<<which;
|
||||
break;
|
||||
case GPIOfalling:
|
||||
gpioregs->falling |= 1<<which;
|
||||
break;
|
||||
case GPIOrising:
|
||||
gpioregs->rising |= 1<<which;
|
||||
break;
|
||||
}
|
||||
unlock(&vctllock);
|
||||
/* point the irq to the gpio interrupt handler */
|
||||
if(gpioirqref[irq]++ == 0)
|
||||
irqenable(irq, gpiointr, nil, "gpio edge");
|
||||
}
|
||||
|
||||
/*
|
||||
* disable an interrupt
|
||||
*/
|
||||
void
|
||||
intrdisable(int type, int which, IntrHandler *f, void* a, char *name)
|
||||
{
|
||||
int irq;
|
||||
Vctl **vp, *v;
|
||||
|
||||
|
||||
if(type == IRQ){
|
||||
irqdisable(which, f, a, name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* from here down, it must be a GPIO edge interrupt */
|
||||
irq = which;
|
||||
if(which >= nelem(gpiovctl) || which < 0)
|
||||
panic("intrdisable");
|
||||
if(which > 11)
|
||||
irq = 11;
|
||||
|
||||
lock(&vctllock);
|
||||
for(vp = &gpiovctl[which]; v = *vp; vp = &v->next)
|
||||
if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
|
||||
break;
|
||||
}
|
||||
if (gpiovctl[which] == nil){
|
||||
/* set edge register to enable interrupt */
|
||||
switch(type){
|
||||
case GPIOboth:
|
||||
print("intrdisable: gpio-rising+falling clear bit %d\n", which);
|
||||
gpioregs->rising &= ~(1<<which);
|
||||
gpioregs->falling &= ~(1<<which);
|
||||
break;
|
||||
case GPIOfalling:
|
||||
print("intrdisable: gpio-falling clear bit %d\n", which);
|
||||
gpioregs->falling &= ~(1<<which);
|
||||
break;
|
||||
case GPIOrising:
|
||||
print("intrdisable: gpio-rising clear bit %d\n", which);
|
||||
gpioregs->rising &= ~(1<<which);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (v) {
|
||||
print("intrdisable: removing %s\n", name);
|
||||
*vp = v->next;
|
||||
}else
|
||||
print("intrdisable: which %d, name %s not enabled\n", which, name);
|
||||
unlock(&vctllock);
|
||||
/* disable the gpio interrupt handler if necessary */
|
||||
if(--gpioirqref[irq] == 0){
|
||||
print("intrdisable: inrqdisable gpiointr\n");
|
||||
irqdisable(irq, gpiointr, nil, "gpio edge");
|
||||
}
|
||||
free(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* called by trap to handle access faults
|
||||
*/
|
||||
static void
|
||||
faultarm(Ureg *ureg, ulong va, int user, int read)
|
||||
{
|
||||
int n, insyscall;
|
||||
char buf[ERRMAX];
|
||||
|
||||
if (up == nil) {
|
||||
warnregs(ureg, "kernel fault");
|
||||
panic("fault: nil up in faultarm, accessing 0x%lux", va);
|
||||
}
|
||||
insyscall = up->insyscall;
|
||||
up->insyscall = 1;
|
||||
n = fault(va, read);
|
||||
if(n < 0){
|
||||
if(!user){
|
||||
warnregs(ureg, "kernel fault");
|
||||
panic("fault: kernel accessing 0x%lux", va);
|
||||
}
|
||||
// warnregs(ureg, "user fault");
|
||||
sprint(buf, "sys: trap: fault %s va=0x%lux", read ? "read" : "write", va);
|
||||
postnote(up, 1, buf, NDebug);
|
||||
}
|
||||
up->insyscall = insyscall;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 1 if the instruction writes memory, 0 otherwise
|
||||
*/
|
||||
int
|
||||
writetomem(ulong inst)
|
||||
{
|
||||
/* swap always write memory */
|
||||
if((inst & 0x0FC00000) == 0x01000000)
|
||||
return 1;
|
||||
|
||||
/* loads and stores are distinguished by bit 20 */
|
||||
if(inst & (1<<20))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* here on all exceptions other than syscall (SWI)
|
||||
*/
|
||||
void
|
||||
trap(Ureg *ureg)
|
||||
{
|
||||
ulong inst;
|
||||
int clockintr, user, x, rv;
|
||||
ulong va, fsr;
|
||||
char buf[ERRMAX];
|
||||
int rem;
|
||||
|
||||
if(up != nil)
|
||||
rem = ((char*)ureg)-up->kstack;
|
||||
else
|
||||
rem = ((char*)ureg)-((char*)(MACHADDR+sizeof(Mach)));
|
||||
if(rem < 256) {
|
||||
dumpstack();
|
||||
panic("trap %d bytes remaining, up = %#p, ureg = %#p, at pc 0x%lux",
|
||||
rem, up, ureg, ureg->pc);
|
||||
}
|
||||
|
||||
user = (ureg->psr & PsrMask) == PsrMusr;
|
||||
|
||||
/*
|
||||
* All interrupts/exceptions should be resumed at ureg->pc-4,
|
||||
* except for Data Abort which resumes at ureg->pc-8.
|
||||
*/
|
||||
if(ureg->type == (PsrMabt+1))
|
||||
ureg->pc -= 8;
|
||||
else
|
||||
ureg->pc -= 4;
|
||||
|
||||
clockintr = 0;
|
||||
switch(ureg->type){
|
||||
default:
|
||||
panic("unknown trap");
|
||||
break;
|
||||
case PsrMirq:
|
||||
clockintr = irq(ureg);
|
||||
break;
|
||||
case PsrMabt: /* prefetch fault */
|
||||
faultarm(ureg, ureg->pc, user, 1);
|
||||
break;
|
||||
case PsrMabt+1: /* data fault */
|
||||
va = getfar();
|
||||
inst = *(ulong*)(ureg->pc);
|
||||
fsr = getfsr() & 0xf;
|
||||
switch(fsr){
|
||||
case 0x0:
|
||||
panic("vector exception at %lux", ureg->pc);
|
||||
break;
|
||||
case 0x1:
|
||||
case 0x3:
|
||||
if(user){
|
||||
snprint(buf, sizeof(buf), "sys: alignment: pc 0x%lux va 0x%lux\n",
|
||||
ureg->pc, va);
|
||||
postnote(up, 1, buf, NDebug);
|
||||
} else
|
||||
panic("kernel alignment: pc 0x%lux va 0x%lux", ureg->pc, va);
|
||||
break;
|
||||
case 0x2:
|
||||
panic("terminal exception at %lux", ureg->pc);
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
case 0x8:
|
||||
case 0xa:
|
||||
case 0xc:
|
||||
case 0xe:
|
||||
panic("external abort 0x%lux pc 0x%lux addr 0x%lux", fsr, ureg->pc, va);
|
||||
break;
|
||||
case 0x5:
|
||||
case 0x7:
|
||||
/* translation fault, i.e., no pte entry */
|
||||
faultarm(ureg, va, user, !writetomem(inst));
|
||||
break;
|
||||
case 0x9:
|
||||
case 0xb:
|
||||
/* domain fault, accessing something we shouldn't */
|
||||
if(user){
|
||||
sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n",
|
||||
ureg->pc, va);
|
||||
postnote(up, 1, buf, NDebug);
|
||||
} else
|
||||
panic("kernel access violation: pc 0x%lux va 0x%lux",
|
||||
ureg->pc, va);
|
||||
break;
|
||||
case 0xd:
|
||||
case 0xf:
|
||||
/* permission error, copy on write or real permission error */
|
||||
faultarm(ureg, va, user, !writetomem(inst));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PsrMund: /* undefined instruction */
|
||||
if (user) {
|
||||
/* look for floating point instructions to interpret */
|
||||
x = spllo();
|
||||
rv = fpiarm(ureg);
|
||||
splx(x);
|
||||
if (rv == 0) {
|
||||
sprint(buf, "undefined instruction: pc 0x%lux\n", ureg->pc);
|
||||
postnote(up, 1, buf, NDebug);
|
||||
}
|
||||
}else{
|
||||
iprint("undefined instruction: pc=0x%lux, inst=0x%lux, 0x%lux, 0x%lux, 0x%lux, 0x%lux\n", ureg->pc, ((ulong*)ureg->pc)[-2], ((ulong*)ureg->pc)[-1], ((ulong*)ureg->pc)[0], ((ulong*)ureg->pc)[1], ((ulong*)ureg->pc)[2]);
|
||||
panic("undefined instruction");
|
||||
}
|
||||
break;
|
||||
}
|
||||
splhi();
|
||||
|
||||
/* delaysched set because we held a lock or because our quantum ended */
|
||||
if(up && up->delaysched && clockintr){
|
||||
sched();
|
||||
splhi();
|
||||
}
|
||||
|
||||
if(user){
|
||||
if(up->procctl || up->nnote)
|
||||
notify(ureg);
|
||||
kexit(ureg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* here on irq's
|
||||
*/
|
||||
static int
|
||||
irq(Ureg *ur)
|
||||
{
|
||||
ulong va;
|
||||
int clockintr, i;
|
||||
Vctl *v;
|
||||
|
||||
va = intrregs->icip;
|
||||
|
||||
if(va & (1<<IRQtimer0))
|
||||
clockintr = 1;
|
||||
else
|
||||
clockintr = 0;
|
||||
for(i = 0; i < 32; i++){
|
||||
if(((1<<i) & va) == 0)
|
||||
continue;
|
||||
for(v = vctl[i]; v != nil; v = v->next){
|
||||
v->f(ur, v->a);
|
||||
va &= ~(1<<i);
|
||||
}
|
||||
}
|
||||
if(va)
|
||||
print("unknown interrupt: %lux\n", va);
|
||||
|
||||
return clockintr;
|
||||
}
|
||||
|
||||
/*
|
||||
* here on gpio interrupts
|
||||
*/
|
||||
static void
|
||||
gpiointr(Ureg *ur, void*)
|
||||
{
|
||||
ulong va;
|
||||
int i;
|
||||
Vctl *v;
|
||||
|
||||
va = gpioregs->edgestatus;
|
||||
gpioregs->edgestatus = va;
|
||||
|
||||
for(i = 0; i < 27; i++){
|
||||
if(((1<<i) & va) == 0)
|
||||
continue;
|
||||
for(v = gpiovctl[i]; v != nil; v = v->next){
|
||||
v->f(ur, v->a);
|
||||
va &= ~(1<<i);
|
||||
}
|
||||
}
|
||||
if(va)
|
||||
print("unknown gpio interrupt: %lux\n", va);
|
||||
}
|
||||
|
||||
/*
|
||||
* system calls
|
||||
*/
|
||||
#include "../port/systab.h"
|
||||
|
||||
/*
|
||||
* Syscall is called directly from assembler without going through trap().
|
||||
*/
|
||||
void
|
||||
syscall(Ureg* ureg)
|
||||
{
|
||||
char *e;
|
||||
ulong sp;
|
||||
long ret;
|
||||
int i, scallnr;
|
||||
|
||||
if((ureg->psr & PsrMask) != PsrMusr) {
|
||||
panic("syscall: pc 0x%lux r14 0x%lux cs 0x%lux", ureg->pc, ureg->r14, ureg->psr);
|
||||
}
|
||||
|
||||
m->syscall++;
|
||||
up->insyscall = 1;
|
||||
up->pc = ureg->pc;
|
||||
up->dbgreg = ureg;
|
||||
|
||||
scallnr = ureg->r0;
|
||||
up->scallnr = scallnr;
|
||||
spllo();
|
||||
|
||||
sp = ureg->sp;
|
||||
up->nerrlab = 0;
|
||||
ret = -1;
|
||||
if(!waserror()){
|
||||
if(scallnr >= nsyscall){
|
||||
pprint("bad sys call number %d pc %lux\n",
|
||||
scallnr, ureg->pc);
|
||||
postnote(up, 1, "sys: bad sys call", NDebug);
|
||||
error(Ebadarg);
|
||||
}
|
||||
|
||||
if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
|
||||
validaddr(sp, sizeof(Sargs)+BY2WD, 0);
|
||||
|
||||
up->s = *((Sargs*)(sp+BY2WD));
|
||||
up->psstate = sysctab[scallnr];
|
||||
|
||||
ret = systab[scallnr]((va_list)up->s.args);
|
||||
poperror();
|
||||
}else{
|
||||
/* failure: save the error buffer for errstr */
|
||||
e = up->syserrstr;
|
||||
up->syserrstr = up->errstr;
|
||||
up->errstr = e;
|
||||
}
|
||||
if(up->nerrlab){
|
||||
print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
|
||||
for(i = 0; i < NERR; i++)
|
||||
print("sp=%lux pc=%lux\n",
|
||||
up->errlab[i].sp, up->errlab[i].pc);
|
||||
panic("error stack");
|
||||
}
|
||||
|
||||
up->insyscall = 0;
|
||||
up->psstate = 0;
|
||||
|
||||
/*
|
||||
* Put return value in frame. On the x86 the syscall is
|
||||
* just another trap and the return value from syscall is
|
||||
* ignored. On other machines the return value is put into
|
||||
* the results register by caller of syscall.
|
||||
*/
|
||||
ureg->r0 = ret;
|
||||
|
||||
if(scallnr == NOTED)
|
||||
noted(ureg, *(ulong*)(sp+BY2WD));
|
||||
|
||||
if(up->delaysched)
|
||||
sched();
|
||||
|
||||
splhi();
|
||||
if(scallnr != RFORK && (up->procctl || up->nnote))
|
||||
notify(ureg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return user to state before notify()
|
||||
*/
|
||||
void
|
||||
noted(Ureg* ureg, ulong arg0)
|
||||
{
|
||||
Ureg *nureg;
|
||||
ulong oureg, sp;
|
||||
|
||||
qlock(&up->debug);
|
||||
if(arg0!=NRSTR && !up->notified) {
|
||||
qunlock(&up->debug);
|
||||
pprint("call to noted() when not notified\n");
|
||||
pexit("Suicide", 0);
|
||||
}
|
||||
up->notified = 0;
|
||||
|
||||
nureg = up->ureg; /* pointer to user returned Ureg struct */
|
||||
|
||||
/* sanity clause */
|
||||
oureg = (ulong)nureg;
|
||||
if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
|
||||
qunlock(&up->debug);
|
||||
pprint("bad ureg in noted or call to noted when not notified\n");
|
||||
pexit("Suicide", 0);
|
||||
}
|
||||
|
||||
/* don't let user change system flags */
|
||||
nureg->psr = (ureg->psr & ~(PsrMask|PsrDfiq|PsrDirq)) |
|
||||
(nureg->psr & (PsrMask|PsrDfiq|PsrDirq));
|
||||
|
||||
memmove(ureg, nureg, sizeof(Ureg));
|
||||
|
||||
switch(arg0){
|
||||
case NCONT:
|
||||
case NRSTR:
|
||||
if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->sp, BY2WD, 0)){
|
||||
qunlock(&up->debug);
|
||||
pprint("suicide: trap in noted\n");
|
||||
pexit("Suicide", 0);
|
||||
}
|
||||
up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
|
||||
qunlock(&up->debug);
|
||||
break;
|
||||
|
||||
case NSAVE:
|
||||
if(!okaddr(nureg->pc, BY2WD, 0)
|
||||
|| !okaddr(nureg->sp, BY2WD, 0)){
|
||||
qunlock(&up->debug);
|
||||
pprint("suicide: trap in noted\n");
|
||||
pexit("Suicide", 0);
|
||||
}
|
||||
qunlock(&up->debug);
|
||||
sp = oureg-4*BY2WD-ERRMAX;
|
||||
splhi();
|
||||
ureg->sp = sp;
|
||||
((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
|
||||
((ulong*)sp)[0] = 0; /* arg 0 is pc */
|
||||
break;
|
||||
|
||||
default:
|
||||
up->lastnote.flag = NDebug;
|
||||
/* fall through */
|
||||
|
||||
case NDFLT:
|
||||
qunlock(&up->debug);
|
||||
if(up->lastnote.flag == NDebug)
|
||||
pprint("suicide: %s\n", up->lastnote.msg);
|
||||
pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Call user, if necessary, with note.
|
||||
* Pass user the Ureg struct and the note on his stack.
|
||||
*/
|
||||
int
|
||||
notify(Ureg* ureg)
|
||||
{
|
||||
int l;
|
||||
ulong s, sp;
|
||||
Note *n;
|
||||
|
||||
if(up->procctl)
|
||||
procctl();
|
||||
if(up->nnote == 0)
|
||||
return 0;
|
||||
|
||||
s = spllo();
|
||||
qlock(&up->debug);
|
||||
up->notepending = 0;
|
||||
n = &up->note[0];
|
||||
if(strncmp(n->msg, "sys:", 4) == 0){
|
||||
l = strlen(n->msg);
|
||||
if(l > ERRMAX-15) /* " pc=0x12345678\0" */
|
||||
l = ERRMAX-15;
|
||||
sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
|
||||
}
|
||||
|
||||
if(n->flag!=NUser && (up->notified || up->notify==0)){
|
||||
qunlock(&up->debug);
|
||||
if(n->flag == NDebug)
|
||||
pprint("suicide: %s\n", n->msg);
|
||||
pexit(n->msg, n->flag!=NDebug);
|
||||
}
|
||||
|
||||
if(up->notified) {
|
||||
qunlock(&up->debug);
|
||||
splhi();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!up->notify){
|
||||
qunlock(&up->debug);
|
||||
pexit(n->msg, n->flag!=NDebug);
|
||||
}
|
||||
sp = ureg->sp;
|
||||
sp -= sizeof(Ureg);
|
||||
|
||||
if(!okaddr((uintptr)up->notify, 1, 0)
|
||||
|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
|
||||
qunlock(&up->debug);
|
||||
pprint("suicide: bad address in notify\n");
|
||||
pexit("Suicide", 0);
|
||||
}
|
||||
|
||||
up->ureg = (void*)sp;
|
||||
memmove((Ureg*)sp, ureg, sizeof(Ureg));
|
||||
*(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
|
||||
up->ureg = (void*)sp;
|
||||
sp -= BY2WD+ERRMAX;
|
||||
memmove((char*)sp, up->note[0].msg, ERRMAX);
|
||||
sp -= 3*BY2WD;
|
||||
*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
|
||||
*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */
|
||||
*(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */
|
||||
ureg->sp = sp;
|
||||
ureg->pc = (ulong)up->notify;
|
||||
up->notified = 1;
|
||||
up->nnote--;
|
||||
memmove(&up->lastnote, &up->note[0], sizeof(Note));
|
||||
memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
|
||||
|
||||
qunlock(&up->debug);
|
||||
splx(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Give enough context in the ureg to produce a kernel stack for
|
||||
* a sleeping process
|
||||
*/
|
||||
void
|
||||
setkernur(Ureg *ureg, Proc *p)
|
||||
{
|
||||
ureg->pc = p->sched.pc;
|
||||
ureg->sp = p->sched.sp+4;
|
||||
ureg->r14 = (ulong)sched;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the userpc the last exception happened at
|
||||
*/
|
||||
uintptr
|
||||
userpc(void)
|
||||
{
|
||||
Ureg *ureg;
|
||||
|
||||
ureg = (Ureg*)up->dbgreg;
|
||||
return ureg->pc;
|
||||
}
|
||||
|
||||
/* This routine must save the values of registers the user is not permitted
|
||||
* to write from devproc and then restore the saved values before returning.
|
||||
*/
|
||||
void
|
||||
setregisters(Ureg* ureg, char* pureg, char* uva, int n)
|
||||
{
|
||||
USED(ureg, pureg, uva, n);
|
||||
}
|
||||
|
||||
/*
|
||||
* this is the body for all kproc's
|
||||
*/
|
||||
static void
|
||||
linkproc(void)
|
||||
{
|
||||
spllo();
|
||||
up->kpfun(up->kparg);
|
||||
pexit("kproc exiting", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* setup stack and initial PC for a new kernel proc. This is architecture
|
||||
* dependent because of the starting stack location
|
||||
*/
|
||||
void
|
||||
kprocchild(Proc *p, void (*func)(void*), void *arg)
|
||||
{
|
||||
p->sched.pc = (ulong)linkproc;
|
||||
p->sched.sp = (ulong)p->kstack+KSTACK;
|
||||
|
||||
p->kpfun = func;
|
||||
p->kparg = arg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Craft a return frame which will cause the child to pop out of
|
||||
* the scheduler in user mode with the return register zero. Set
|
||||
* pc to point to a l.s return function.
|
||||
*/
|
||||
void
|
||||
forkchild(Proc *p, Ureg *ureg)
|
||||
{
|
||||
Ureg *cureg;
|
||||
|
||||
//print("%lud setting up for forking child %lud\n", up->pid, p->pid);
|
||||
p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
|
||||
p->sched.pc = (ulong)forkret;
|
||||
|
||||
cureg = (Ureg*)(p->sched.sp);
|
||||
memmove(cureg, ureg, sizeof(Ureg));
|
||||
|
||||
/* syscall returns 0 for child */
|
||||
cureg->r0 = 0;
|
||||
|
||||
/* Things from bottom of syscall which were never executed */
|
||||
p->psstate = 0;
|
||||
p->insyscall = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup stack, initial PC, and any arch dependent regs for an execing user proc.
|
||||
*/
|
||||
uintptr
|
||||
execregs(uintptr entry, ulong ssize, ulong nargs)
|
||||
{
|
||||
ulong *sp;
|
||||
Ureg *ureg;
|
||||
|
||||
sp = (ulong*)(USTKTOP - ssize);
|
||||
*--sp = nargs;
|
||||
|
||||
ureg = up->dbgreg;
|
||||
memset(ureg, 0, 15*sizeof(ulong));
|
||||
ureg->r13 = (ulong)sp;
|
||||
ureg->pc = entry;
|
||||
//print("%lud: EXECREGS pc 0x%lux sp 0x%lux\n", up->pid, ureg->pc, ureg->r13);
|
||||
return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in enough of Ureg to get a stack trace, and call a function.
|
||||
* Used by debugging interface rdb.
|
||||
*/
|
||||
void
|
||||
callwithureg(void (*fn)(Ureg*))
|
||||
{
|
||||
Ureg ureg;
|
||||
ureg.pc = getcallerpc(&fn);
|
||||
ureg.sp = (ulong)&fn;
|
||||
fn(&ureg);
|
||||
}
|
||||
|
||||
static void
|
||||
_dumpstack(Ureg *ureg)
|
||||
{
|
||||
ulong l, v, i;
|
||||
ulong *p;
|
||||
extern ulong etext;
|
||||
|
||||
if(up == 0){
|
||||
iprint("no current proc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
iprint("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->r14);
|
||||
i = 0;
|
||||
for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
|
||||
v = *(ulong*)l;
|
||||
if(KTZERO < v && v < (ulong)&etext && (v&3)==0){
|
||||
v -= 4;
|
||||
p = (ulong*)v;
|
||||
if((*p & 0x0f000000) == 0x0b000000){
|
||||
iprint("%.8lux=%.8lux ", l, v);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if(i == 4){
|
||||
i = 0;
|
||||
iprint("\n");
|
||||
}
|
||||
}
|
||||
if(i)
|
||||
iprint("\n");
|
||||
}
|
||||
|
||||
void
|
||||
dumpstack(void)
|
||||
{
|
||||
callwithureg(_dumpstack);
|
||||
}
|
||||
|
||||
/*
|
||||
* pc output by ps
|
||||
*/
|
||||
uintptr
|
||||
dbgpc(Proc *p)
|
||||
{
|
||||
Ureg *ureg;
|
||||
|
||||
ureg = p->dbgreg;
|
||||
if(ureg == 0)
|
||||
return 0;
|
||||
|
||||
return ureg->pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* called in sysfile.c
|
||||
*/
|
||||
void
|
||||
evenaddr(ulong addr)
|
||||
{
|
||||
if(addr & 3){
|
||||
postnote(up, 1, "sys: odd address", NDebug);
|
||||
error(Ebadarg);
|
||||
}
|
||||
}
|
|
@ -1,514 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
#include "../port/netif.h"
|
||||
|
||||
/* this isn't strictly an sa1110 driver. The rts/cts stuff is h3650 specific */
|
||||
|
||||
static void sa1110_uartpower(Uart *, int);
|
||||
|
||||
enum
|
||||
{
|
||||
/* ctl[0] bits */
|
||||
Parity= 1<<0,
|
||||
Even= 1<<1,
|
||||
Stop2= 1<<2,
|
||||
Bits8= 1<<3,
|
||||
SCE= 1<<4, /* synchronous clock enable */
|
||||
RCE= 1<<5, /* rx on falling edge of clock */
|
||||
TCE= 1<<6, /* tx on falling edge of clock */
|
||||
|
||||
/* ctl[3] bits */
|
||||
Rena= 1<<0, /* receiver enable */
|
||||
Tena= 1<<1, /* transmitter enable */
|
||||
Break= 1<<2, /* force TXD3 low */
|
||||
Rintena= 1<<3, /* enable receive interrupt */
|
||||
Tintena= 1<<4, /* enable transmitter interrupt */
|
||||
Loopback= 1<<5, /* loop back data */
|
||||
|
||||
/* data bits */
|
||||
DEparity= 1<<8, /* parity error */
|
||||
DEframe= 1<<9, /* framing error */
|
||||
DEoverrun= 1<<10, /* overrun error */
|
||||
|
||||
/* status[0] bits */
|
||||
Tint= 1<<0, /* transmit fifo half full interrupt */
|
||||
Rint0= 1<<1, /* receiver fifo 1/3-2/3 full */
|
||||
Rint1= 1<<2, /* receiver fifo not empty and receiver idle */
|
||||
Breakstart= 1<<3,
|
||||
Breakend= 1<<4,
|
||||
Fifoerror= 1<<5, /* fifo error */
|
||||
|
||||
/* status[1] bits */
|
||||
Tbusy= 1<<0, /* transmitting */
|
||||
Rnotempty= 1<<1, /* receive fifo not empty */
|
||||
Tnotfull= 1<<2, /* transmit fifo not full */
|
||||
ParityError= 1<<3,
|
||||
FrameError= 1<<4,
|
||||
Overrun= 1<<5,
|
||||
};
|
||||
|
||||
extern PhysUart sa1110physuart;
|
||||
|
||||
//static
|
||||
Uart sa1110uart[2] = {
|
||||
{ .regs = (void*)UART3REGS,
|
||||
.name = "serialport3",
|
||||
.freq = ClockFreq,
|
||||
.bits = 8,
|
||||
.stop = 1,
|
||||
.parity = 'n',
|
||||
.baud = 115200,
|
||||
.phys = &sa1110physuart,
|
||||
.special = 0,
|
||||
.next = &sa1110uart[1], },
|
||||
|
||||
{ .regs = (void*)UART1REGS,
|
||||
.name = "serialport1",
|
||||
.freq = ClockFreq,
|
||||
.bits = 8,
|
||||
.stop = 1,
|
||||
.parity = 'n',
|
||||
.baud = 115200,
|
||||
.phys = &sa1110physuart,
|
||||
.putc = µcputc,
|
||||
.special = 0,
|
||||
.next = nil, },
|
||||
};
|
||||
static Uart* µcuart;
|
||||
|
||||
#define R(p) ((Uartregs*)((p)->regs))
|
||||
#define SR(p) ((Uartregs*)((p)->saveregs))
|
||||
|
||||
/*
|
||||
* enable a port's interrupts. set DTR and RTS
|
||||
*/
|
||||
static void
|
||||
sa1110_uartenable(Uart *p, int intena)
|
||||
{
|
||||
ulong s;
|
||||
|
||||
s = R(p)->ctl[3] & ~(Rintena|Tintena|Rena|Tena);
|
||||
if(intena)
|
||||
R(p)->ctl[3] = s |Rintena|Tintena|Rena|Tena;
|
||||
else
|
||||
R(p)->ctl[3] = s | Rena|Tena;
|
||||
}
|
||||
|
||||
/*
|
||||
* disable interrupts. clear DTR, and RTS
|
||||
*/
|
||||
static void
|
||||
sa1110_uartdisable(Uart *p)
|
||||
{
|
||||
R(p)->ctl[3] &= ~(Rintena|Tintena|Rena|Tena);
|
||||
}
|
||||
|
||||
static long
|
||||
sa1110_uartstatus(Uart *p, void *buf, long n, long offset)
|
||||
{
|
||||
char str[256];
|
||||
ulong ctl0;
|
||||
|
||||
ctl0 = R(p)->ctl[0];
|
||||
snprint(str, sizeof(str),
|
||||
"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
|
||||
"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
|
||||
|
||||
p->baud,
|
||||
p->hup_dcd,
|
||||
0,
|
||||
p->hup_dsr,
|
||||
(ctl0 & Bits8) ? 8 : 7,
|
||||
0,
|
||||
(ctl0 & Parity) ? ((ctl0 & Even) ? 'e' : 'o') : 'n',
|
||||
0,
|
||||
(ctl0 & Stop2) ? 2 : 1,
|
||||
1,
|
||||
|
||||
p->dev,
|
||||
p->type,
|
||||
p->ferr,
|
||||
p->oerr,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"" );
|
||||
return readstr(offset, buf, n, str);
|
||||
}
|
||||
|
||||
/*
|
||||
* set the buad rate
|
||||
*/
|
||||
static int
|
||||
sa1110_uartbaud(Uart *p, int rate)
|
||||
{
|
||||
ulong brconst;
|
||||
ulong ctl3;
|
||||
|
||||
if(rate <= 0)
|
||||
return -1;
|
||||
|
||||
/* disable */
|
||||
ctl3 = R(p)->ctl[3];
|
||||
R(p)->ctl[3] = 0;
|
||||
|
||||
brconst = p->freq/(16*rate) - 1;
|
||||
R(p)->ctl[1] = (brconst>>8) & 0xf;
|
||||
R(p)->ctl[2] = brconst & 0xff;
|
||||
|
||||
/* reenable */
|
||||
R(p)->ctl[3] = ctl3;
|
||||
|
||||
p->baud = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* send a break
|
||||
*/
|
||||
static void
|
||||
sa1110_uartbreak(Uart *p, int ms)
|
||||
{
|
||||
if(ms == 0)
|
||||
ms = 200;
|
||||
|
||||
R(p)->ctl[3] |= Break;
|
||||
tsleep(&up->sleep, return0, 0, ms);
|
||||
R(p)->ctl[3] &= ~Break;
|
||||
}
|
||||
|
||||
/*
|
||||
* set bits/char
|
||||
*/
|
||||
static int
|
||||
sa1110_uartbits(Uart *p, int n)
|
||||
{
|
||||
ulong ctl0, ctl3;
|
||||
|
||||
ctl0 = R(p)->ctl[0];
|
||||
switch(n){
|
||||
case 7:
|
||||
ctl0 &= ~Bits8;
|
||||
break;
|
||||
case 8:
|
||||
ctl0 |= Bits8;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* disable */
|
||||
ctl3 = R(p)->ctl[3];
|
||||
R(p)->ctl[3] = 0;
|
||||
|
||||
R(p)->ctl[0] = ctl0;
|
||||
|
||||
/* reenable */
|
||||
R(p)->ctl[3] = ctl3;
|
||||
|
||||
p->bits = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set stop bits
|
||||
*/
|
||||
static int
|
||||
sa1110_uartstop(Uart *p, int n)
|
||||
{
|
||||
ulong ctl0, ctl3;
|
||||
|
||||
ctl0 = R(p)->ctl[0];
|
||||
switch(n){
|
||||
case 1:
|
||||
ctl0 &= ~Stop2;
|
||||
break;
|
||||
case 2:
|
||||
ctl0 |= Stop2;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* disable */
|
||||
ctl3 = R(p)->ctl[3];
|
||||
R(p)->ctl[3] = 0;
|
||||
|
||||
R(p)->ctl[0] = ctl0;
|
||||
|
||||
/* reenable */
|
||||
R(p)->ctl[3] = ctl3;
|
||||
|
||||
p->stop = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* turn on/off rts
|
||||
*/
|
||||
static void
|
||||
sa1110_uartrts(Uart*, int)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* turn on/off dtr
|
||||
*/
|
||||
static void
|
||||
sa1110_uartdtr(Uart*, int)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* turn on/off modem flow control on/off (rts/cts)
|
||||
*/
|
||||
static void
|
||||
sa1110_uartmodemctl(Uart *p, int on)
|
||||
{
|
||||
if(on) {
|
||||
} else {
|
||||
p->cts = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set parity
|
||||
*/
|
||||
static int
|
||||
sa1110_uartparity(Uart *p, int type)
|
||||
{
|
||||
ulong ctl0, ctl3;
|
||||
|
||||
ctl0 = R(p)->ctl[0];
|
||||
switch(type){
|
||||
case 'e':
|
||||
ctl0 |= Parity|Even;
|
||||
break;
|
||||
case 'o':
|
||||
ctl0 |= Parity;
|
||||
break;
|
||||
default:
|
||||
ctl0 &= ~(Parity|Even);
|
||||
break;
|
||||
}
|
||||
|
||||
/* disable */
|
||||
ctl3 = R(p)->ctl[3];
|
||||
R(p)->ctl[3] = 0;
|
||||
|
||||
R(p)->ctl[0] = ctl0;
|
||||
|
||||
/* reenable */
|
||||
R(p)->ctl[3] = ctl3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* restart output if not blocked and OK to send
|
||||
*/
|
||||
static void
|
||||
sa1110_uartkick(Uart *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
R(p)->ctl[3] &= ~Tintena;
|
||||
|
||||
if(p->cts == 0 || p->blocked)
|
||||
return;
|
||||
|
||||
for(i = 0; i < 1024; i++){
|
||||
if(!(R(p)->status[1] & Tnotfull)){
|
||||
R(p)->ctl[3] |= Tintena;
|
||||
break;
|
||||
}
|
||||
if(p->op >= p->oe && uartstageoutput(p) == 0)
|
||||
break;
|
||||
R(p)->data = *p->op++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* take an interrupt
|
||||
*/
|
||||
static void
|
||||
sa1110_uartintr(Ureg*, void *x)
|
||||
{
|
||||
Uart *p;
|
||||
ulong s;
|
||||
Uartregs *regs;
|
||||
|
||||
p = x;
|
||||
regs = p->regs;
|
||||
|
||||
/* receiver interrupt, snarf bytes */
|
||||
while(regs->status[1] & Rnotempty)
|
||||
uartrecv(p, regs->data);
|
||||
|
||||
/* remember and reset interrupt causes */
|
||||
s = regs->status[0];
|
||||
regs->status[0] |= s;
|
||||
|
||||
if(s & Tint){
|
||||
/* transmitter interrupt, restart */
|
||||
uartkick(p);
|
||||
}
|
||||
|
||||
if(s & (ParityError|FrameError|Overrun)){
|
||||
if(s & ParityError)
|
||||
p->parity++;
|
||||
if(s & FrameError)
|
||||
p->ferr++;
|
||||
if(s & Overrun)
|
||||
p->oerr++;
|
||||
}
|
||||
|
||||
/* receiver interrupt, snarf bytes */
|
||||
while(regs->status[1] & Rnotempty)
|
||||
uartrecv(p, regs->data);
|
||||
}
|
||||
|
||||
static Uart*
|
||||
sa1110_pnp(void)
|
||||
{
|
||||
return sa1110uart;
|
||||
}
|
||||
|
||||
static int
|
||||
sa1110_getc(Uart *uart)
|
||||
{
|
||||
Uartregs *ur;
|
||||
|
||||
ur = uart->regs;
|
||||
while((ur->status[1] & Rnotempty) == 0)
|
||||
;
|
||||
return ur->data;
|
||||
}
|
||||
|
||||
static void
|
||||
sa1110_putc(Uart *uart, int c)
|
||||
{
|
||||
Uartregs *ur;
|
||||
|
||||
ur = uart->regs;
|
||||
/* wait for output ready */
|
||||
while((ur->status[1] & Tnotfull) == 0)
|
||||
;
|
||||
ur->data = c;
|
||||
while((ur->status[1] & Tbusy))
|
||||
;
|
||||
}
|
||||
|
||||
PhysUart sa1110physuart = {
|
||||
.name= "sa1110",
|
||||
.pnp= sa1110_pnp,
|
||||
.enable= sa1110_uartenable,
|
||||
.disable= sa1110_uartdisable,
|
||||
.bits= sa1110_uartbits,
|
||||
.kick= sa1110_uartkick,
|
||||
.modemctl= sa1110_uartmodemctl,
|
||||
.baud= sa1110_uartbaud,
|
||||
.stop= sa1110_uartstop,
|
||||
.parity= sa1110_uartparity,
|
||||
.dobreak= sa1110_uartbreak,
|
||||
.rts= sa1110_uartrts,
|
||||
.dtr= sa1110_uartdtr,
|
||||
.status= sa1110_uartstatus,
|
||||
.power= sa1110_uartpower,
|
||||
.getc= sa1110_getc,
|
||||
.putc= sa1110_putc,
|
||||
};
|
||||
|
||||
/*
|
||||
* for iprint, just write it
|
||||
*/
|
||||
void
|
||||
serialµcputs(uchar *str, int n)
|
||||
{
|
||||
Uartregs *ur;
|
||||
|
||||
if(µcuart == nil)
|
||||
return;
|
||||
ur = µcuart->regs;
|
||||
while(n-- > 0){
|
||||
/* wait for output ready */
|
||||
while((ur->status[1] & Tnotfull) == 0)
|
||||
;
|
||||
ur->data = *str++;
|
||||
}
|
||||
while((ur->status[1] & Tbusy))
|
||||
;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
/* gpclk register 0 */
|
||||
Gpclk_sus= 1<<0, /* set uart mode */
|
||||
};
|
||||
|
||||
Gpclkregs *gpclkregs;
|
||||
|
||||
/*
|
||||
* setup all uarts (called early by main() to allow debugging output to
|
||||
* a serial port)
|
||||
*/
|
||||
void
|
||||
sa1110_uartsetup(int console)
|
||||
{
|
||||
Uart *p;
|
||||
|
||||
/* external serial port (eia0) */
|
||||
p = &sa1110uart[0];
|
||||
p->regs = mapspecial(UART3REGS, sizeof(Uartregs));
|
||||
p->saveregs = xalloc(sizeof(Uartregs));
|
||||
/* set eia0 up as a console */
|
||||
if(console){
|
||||
uartctl(p, "b115200 l8 pn s1");
|
||||
(*p->phys->enable)(p, 0);
|
||||
p->console = 1;
|
||||
consuart = p;
|
||||
}
|
||||
intrenable(IRQ, IRQuart3, sa1110_uartintr, p, p->name);
|
||||
|
||||
/* port for talking to microcontroller (eia1) */
|
||||
gpclkregs = mapspecial(GPCLKREGS, sizeof(Gpclkregs));
|
||||
gpclkregs->r0 = Gpclk_sus; /* set uart mode */
|
||||
|
||||
p = &sa1110uart[1];
|
||||
p->regs = mapspecial(UART1REGS, sizeof(Uartregs));
|
||||
p->saveregs = xalloc(sizeof(Uartregs));
|
||||
uartctl(p, "b115200 l8 pn s1");
|
||||
µcuart = p;
|
||||
p->special = 1;
|
||||
(*p->phys->enable)(p, 0);
|
||||
intrenable(IRQ, IRQuart1b, sa1110_uartintr, p, p->name);
|
||||
}
|
||||
|
||||
static void
|
||||
uartcpy(Uartregs *to, Uartregs *from)
|
||||
{
|
||||
to->ctl[0] = from->ctl[0];
|
||||
// to->ctl[1] = from->ctl[1];
|
||||
// to->ctl[2] = from->ctl[2];
|
||||
to->ctl[3] = from->ctl[3];
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
sa1110_uartpower(Uart *p, int powerup)
|
||||
{
|
||||
if (powerup) {
|
||||
/* power up, restore the registers */
|
||||
uartcpy(R(p), SR(p));
|
||||
R(p)->status[0] = R(p)->status[0];
|
||||
} else {
|
||||
/* power down, save the registers */
|
||||
uartcpy(SR(p), R(p));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1 +0,0 @@
|
|||
#include "../pc/wavelan.h"
|
|
@ -1,6 +1,5 @@
|
|||
ARCH=\
|
||||
bcm\
|
||||
bitsy\
|
||||
kw\
|
||||
mtx\
|
||||
omap\
|
||||
|
|
Loading…
Reference in a new issue