Merge branch 'front' of git://git.9front.org/plan9front/plan9front into front
This commit is contained in:
commit
58fe4bd42c
72 changed files with 7965 additions and 279 deletions
1
lib/rob
1
lib/rob
|
@ -399,3 +399,4 @@ Over time, everything gets better but also worse and always bigger and more comp
|
|||
Nice to see Egreg again.
|
||||
It wasn't my intention.
|
||||
The Blit was nice.
|
||||
Sockets are just so unpleasant, and the endless nonsense around network configuration doubly so.
|
||||
|
|
|
@ -27,7 +27,7 @@ struct Ndb
|
|||
Ndb *next;
|
||||
|
||||
Biobufhdr b; /* buffered input file */
|
||||
uchar buf[256]; /* and its buffer */
|
||||
uchar buf[8192]; /* and its buffer */
|
||||
|
||||
ulong mtime; /* mtime of db file */
|
||||
Qid qid; /* qid of db file */
|
||||
|
|
26
sys/lib/dist/mkfile
vendored
26
sys/lib/dist/mkfile
vendored
|
@ -77,7 +77,7 @@ cd:V: /tmp/9front.386.iso.gz
|
|||
mv $target.$pid.disk $target
|
||||
}
|
||||
|
||||
%.zynq.img:
|
||||
%.zynq.img:D:
|
||||
@{
|
||||
objtype=arm
|
||||
kernel=/n/src9/$objtype/9zynq
|
||||
|
@ -88,6 +88,16 @@ cd:V: /tmp/9front.386.iso.gz
|
|||
mv $target.$pid.disk $target
|
||||
}
|
||||
|
||||
%.reform.img:D: /n/src9/sys/src/boot/reform/flash.bin /n/src9/sys/src/boot/reform/boot.scr
|
||||
@{
|
||||
objtype=arm64
|
||||
kernel=/n/src9/$objtype/9reform.u
|
||||
fatfiles=(/n/src9/sys/src/boot/reform/boot.scr $kernel)
|
||||
mb=1885 # storage vendors idea of 2GB
|
||||
mk $target.$pid.disk
|
||||
mv $target.$pid.disk $target && dd -trunc 0 -bs 1024 -oseek 33 -if /n/src9/sys/src/boot/reform/flash.bin -of $target
|
||||
}
|
||||
|
||||
%.pc.iso:D: $proto /n/src9/sys/lib/sysconfig/proto/9bootproto $kernel
|
||||
@{rfork n
|
||||
mk binds
|
||||
|
@ -142,6 +152,20 @@ cd:V: /tmp/9front.386.iso.gz
|
|||
disk/prep -bw -a^(nvram fs) $d/plan9
|
||||
disk/format -d $d/dos $fatfiles
|
||||
}
|
||||
if not if(~ $target *.reform.img.*){
|
||||
{
|
||||
echo 'a p1 4M 100M'
|
||||
echo 't p1 FAT32'
|
||||
echo 'a p2 . $'
|
||||
echo 't p2 PLAN9'
|
||||
echo 'A p1'
|
||||
echo 'p'
|
||||
echo 'w'
|
||||
echo 'q'
|
||||
} | disk/fdisk -b $d/data
|
||||
disk/prep -bw -a^(nvram fs) $d/plan9
|
||||
disk/format -d $d/dos $fatfiles
|
||||
}
|
||||
if not {
|
||||
disk/fdisk -baw $d/data
|
||||
disk/prep -bw -a^(9fat nvram fs) $d/plan9
|
||||
|
|
86
sys/man/1/patch
Normal file
86
sys/man/1/patch
Normal file
|
@ -0,0 +1,86 @@
|
|||
.TH PATCH 1
|
||||
.SH NAME
|
||||
patch \- apply patches
|
||||
.SH SYNOPSIS
|
||||
.B patch
|
||||
[
|
||||
.B -R
|
||||
]
|
||||
[
|
||||
.B -p
|
||||
.I nstrip
|
||||
]
|
||||
[
|
||||
.I patch ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Patch
|
||||
scans its input for a sequence of patches, and applies them, printing the list of changed files.
|
||||
When an applied patch does not match precisely,
|
||||
.I patch
|
||||
will scan the input file for matching context, applying the patch up to 250 lines away from
|
||||
its original location.
|
||||
If a hunk does not apply, then the file is left untouched.
|
||||
.PP
|
||||
The following options are supported:
|
||||
.TP
|
||||
.B -R
|
||||
Reverse direction of the patch. Additions become removals,
|
||||
and the new and old file names are swapped.
|
||||
.TP
|
||||
.BI -p \ nstrip
|
||||
Remove the prefix containing
|
||||
.I nstrip
|
||||
leading slashes from each file path in the diff file.
|
||||
.SH INPUT FORMAT
|
||||
A patch begins with a patch header, and is followed by a sequence of one or more hunks.
|
||||
All lines before a patch header or after the last hunk of a patch are comments,
|
||||
and are ignored by patch. A patch header is a sequence of 2 lines in the following
|
||||
format:
|
||||
.IP
|
||||
.EX
|
||||
--- oldfile [trailing text]
|
||||
+++ newfile [trailing text]
|
||||
.EE
|
||||
.PP
|
||||
A hunk must immediately follow a patch header or another hunk.
|
||||
It begins with a header line in the following format:
|
||||
.IP
|
||||
.EX
|
||||
@@ -count,addr +count,addr @@
|
||||
.EE
|
||||
.PP
|
||||
And contains a sequence of lines beginning with a
|
||||
.LR - ,
|
||||
.LR + ,
|
||||
or space characters.
|
||||
A
|
||||
.L -
|
||||
indicates that the line is to be removed from the old file.
|
||||
A
|
||||
.L +
|
||||
indicates that the line is to be inserted into the new file.
|
||||
A space indicates that the line is context.
|
||||
It will be copied unchanged from the old file to the new file.
|
||||
.PP
|
||||
If the old file is
|
||||
.LR /dev/null ,
|
||||
the patch indicates a file creation.
|
||||
If the new file is
|
||||
.LR /dev/null ,
|
||||
the patch indicates a file deletion.
|
||||
In this case, the file printed is the file being removed.
|
||||
.SH SEE ALSO
|
||||
.IR diff (1),
|
||||
.IR git/export (1)
|
||||
.SH BUGS
|
||||
.PP
|
||||
The output of
|
||||
.B diff -c
|
||||
is not handled.
|
||||
.PP
|
||||
Reject files and backups are not supported.
|
||||
.PP
|
||||
All files are processed in memory, limiting the maximum file size to available RAM.
|
||||
|
||||
|
|
@ -5,6 +5,8 @@ srv \- server registry
|
|||
.nf
|
||||
.B bind #s /srv
|
||||
|
||||
.BI #s/ clone
|
||||
.BI #s/ n
|
||||
.BI #s/ service1
|
||||
.BI #s/ service2
|
||||
...
|
||||
|
@ -12,7 +14,7 @@ srv \- server registry
|
|||
.SH DESCRIPTION
|
||||
The
|
||||
.I srv
|
||||
device provides a one-level directory holding
|
||||
device provides a tree of directories holding
|
||||
already-open channels to services.
|
||||
In effect,
|
||||
.I srv
|
||||
|
@ -40,6 +42,18 @@ releases that reference.
|
|||
.PP
|
||||
It is an error to write more than one number into a server file,
|
||||
or to create a file with a name that is already being used.
|
||||
.PP
|
||||
Opening the
|
||||
.I clone
|
||||
file allocates a new service directory. Reading
|
||||
.I clone
|
||||
returns the id of the new directory. This new service
|
||||
directory can then be accessed at
|
||||
.BR /srv/id .
|
||||
Directories are recursable; each new service directory
|
||||
contains its own
|
||||
.I clone
|
||||
file.
|
||||
.SH EXAMPLE
|
||||
To drop one end of a pipe into
|
||||
.BR /srv ,
|
||||
|
|
65
sys/man/4/skelfs
Normal file
65
sys/man/4/skelfs
Normal file
|
@ -0,0 +1,65 @@
|
|||
.TH SKELFS 4
|
||||
.SH NAME
|
||||
skelfs \- build directory skeletons
|
||||
.SH SYNOPSIS
|
||||
.B skelfs
|
||||
[
|
||||
.B -i
|
||||
]
|
||||
[
|
||||
.B -t
|
||||
.I mode
|
||||
]
|
||||
[
|
||||
.B -s
|
||||
.I service
|
||||
]
|
||||
[
|
||||
.I mnt
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Skelfs
|
||||
generates directory skeletons
|
||||
to assist in building namespaces.
|
||||
Skeletons are generated on demand
|
||||
by walking through the root directory.
|
||||
A skeleon is a directory containing a single empty child.
|
||||
The name of this child is defined by the first walk taken
|
||||
away from the root. For example the hierarchy for a skeleton
|
||||
named 'echo' would be:
|
||||
.PP
|
||||
.EX
|
||||
/
|
||||
/echo/
|
||||
/echo/echo
|
||||
.EE
|
||||
.PP
|
||||
The
|
||||
.I mode
|
||||
dictates what form the innermost child file takes. The
|
||||
.B file
|
||||
and
|
||||
.B dir
|
||||
modes cause the child to be an empty file or directory
|
||||
respecively. The
|
||||
.B empty
|
||||
mode instead serves no skeletons, causing the root
|
||||
directory to always be empty.
|
||||
A client may override the mode by providing
|
||||
its own selection as an attach option. If a
|
||||
mode is not provided,
|
||||
.B file
|
||||
is assumed.
|
||||
.PP
|
||||
The skeletons generated by
|
||||
.I skelfs
|
||||
are anonmyous. Clients will never see the
|
||||
skeletons of other clients, nor can a client revisit
|
||||
a previous skeleton.
|
||||
.PP
|
||||
.SH "SEE ALSO"
|
||||
.B auth/box
|
||||
in
|
||||
.IR auth (8).
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/skelfs.c
|
|
@ -60,6 +60,20 @@ changeuser, convkeys, printnetkey, status, enable, disable, authsrv, guard.srv,
|
|||
.I arg
|
||||
\&...
|
||||
.PP
|
||||
.B auth/box
|
||||
[
|
||||
.B -d
|
||||
] [
|
||||
.B -rc
|
||||
.I file
|
||||
] [
|
||||
.B -e
|
||||
.I devs
|
||||
]
|
||||
.I command
|
||||
.I arg
|
||||
\&...
|
||||
.PP
|
||||
.B auth/as
|
||||
[
|
||||
.B -d
|
||||
|
@ -264,6 +278,26 @@ If there are no arguments, it
|
|||
It's an easy way to run a command as
|
||||
.IR none .
|
||||
.PP
|
||||
.I Box
|
||||
executes its arguments in a minimal namespace.
|
||||
This namespace is derived by binding in the specified
|
||||
program to the same name within a new hierarchy.
|
||||
The same is done with the paths
|
||||
provided as arguments. Paths provided with the
|
||||
.B -r
|
||||
flag are bound with
|
||||
.IR MREPL ,
|
||||
and those provided with the
|
||||
.B -c
|
||||
flag are bound with
|
||||
.IR MCREATE .
|
||||
.I Box
|
||||
removes access to all kernel drivers from
|
||||
the child namespace; the
|
||||
.B -e
|
||||
flag specifies a string of driver
|
||||
characters to keep.
|
||||
.PP
|
||||
.I As
|
||||
executes
|
||||
.I command
|
||||
|
@ -299,5 +333,3 @@ in
|
|||
.IR authsrv (2),
|
||||
.IR keyfs (4),
|
||||
.IR securenet (8)
|
||||
.SH BUGS
|
||||
Only CPU kernels permit changing userid.
|
||||
|
|
|
@ -712,6 +712,12 @@ Suppress the
|
|||
prompt and use
|
||||
.I value
|
||||
as the answer instead.
|
||||
.SS \fLbootloop=\fIvalue\fP
|
||||
Always use
|
||||
.I value
|
||||
as the answer to the
|
||||
.L bootargs
|
||||
prompt, retrying if unsuccessful.
|
||||
.SS \fLrootdir=\fB/root/\fIdir\fP
|
||||
.SS \fLrootspec=\fIspec\fP
|
||||
Changes the mount arguments for the root file server
|
||||
|
|
|
@ -68,6 +68,11 @@ mt=()
|
|||
fn main{
|
||||
mp=()
|
||||
while(~ $#mp 0){
|
||||
if(! ~ $#bootloop 0){
|
||||
nobootprompt=$bootloop
|
||||
# 'flatten' for the next boot
|
||||
echo -n $bootloop > '#ec/bootloop'
|
||||
}
|
||||
if(~ $#nobootprompt 0){
|
||||
echo
|
||||
showlocaldevs
|
||||
|
|
|
@ -32,6 +32,7 @@ fn connectreboot {
|
|||
|
||||
# set new kernel parameters
|
||||
echo -n $bootargs > '#ec/bootargs'
|
||||
rm -f '#ec/bootloop'
|
||||
|
||||
# remove part of our temporary root
|
||||
/mnt/broot/$cputype/bin/unmount /$cputype/bin /bin
|
||||
|
|
1357
sys/src/9/imx8/ccm.c
Normal file
1357
sys/src/9/imx8/ccm.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,10 @@
|
|||
#include "../port/ethermii.h"
|
||||
|
||||
enum {
|
||||
Moduleclk = 125000000, /* 125Mhz */
|
||||
Ptpclk = 100*Mhz,
|
||||
Busclk = 266*Mhz,
|
||||
Txclk = 125*Mhz,
|
||||
|
||||
Maxtu = 1518,
|
||||
|
||||
R_BUF_SIZE = ((Maxtu+BLOCKALIGN-1)&~BLOCKALIGN),
|
||||
|
@ -231,6 +234,7 @@ struct Ctlr
|
|||
|
||||
struct {
|
||||
Mii;
|
||||
int done;
|
||||
Rendez;
|
||||
} mii[1];
|
||||
|
||||
|
@ -245,7 +249,7 @@ static int
|
|||
mdiodone(void *arg)
|
||||
{
|
||||
Ctlr *ctlr = arg;
|
||||
return rr(ctlr, ENET_EIR) & INT_MII;
|
||||
return ctlr->mii->done || (rr(ctlr, ENET_EIR) & INT_MII) != 0;
|
||||
}
|
||||
static int
|
||||
mdiowait(Ctlr *ctlr)
|
||||
|
@ -265,9 +269,13 @@ mdiow(Mii* mii, int phy, int addr, int data)
|
|||
Ctlr *ctlr = mii->ctlr;
|
||||
|
||||
data &= 0xFFFF;
|
||||
|
||||
wr(ctlr, ENET_EIR, INT_MII);
|
||||
ctlr->mii->done = 0;
|
||||
|
||||
wr(ctlr, ENET_MMFR, MMFR_WR | MMFR_ST | MMFR_TA | phy<<MMFR_PA_SHIFT | addr<<MMFR_RA_SHIFT | data);
|
||||
if(mdiowait(ctlr) < 0) return -1;
|
||||
if(mdiowait(ctlr) < 0)
|
||||
return -1;
|
||||
return data;
|
||||
}
|
||||
static int
|
||||
|
@ -276,8 +284,11 @@ mdior(Mii* mii, int phy, int addr)
|
|||
Ctlr *ctlr = mii->ctlr;
|
||||
|
||||
wr(ctlr, ENET_EIR, INT_MII);
|
||||
ctlr->mii->done = 0;
|
||||
|
||||
wr(ctlr, ENET_MMFR, MMFR_RD | MMFR_ST | MMFR_TA | phy<<MMFR_PA_SHIFT | addr<<MMFR_RA_SHIFT);
|
||||
if(mdiowait(ctlr) < 0) return -1;
|
||||
if(mdiowait(ctlr) < 0)
|
||||
return -1;
|
||||
return rr(ctlr, ENET_MMFR) & 0xFFFF;
|
||||
}
|
||||
|
||||
|
@ -289,11 +300,13 @@ interrupt(Ureg*, void *arg)
|
|||
u32int e;
|
||||
|
||||
e = rr(ctlr, ENET_EIR);
|
||||
wr(ctlr, ENET_EIR, e);
|
||||
|
||||
if(e & INT_RXF) wakeup(ctlr->rx);
|
||||
if(e & INT_TXF) wakeup(ctlr->tx);
|
||||
if(e & INT_MII) wakeup(ctlr->mii);
|
||||
if(e & INT_MII) {
|
||||
ctlr->mii->done = 1;
|
||||
wakeup(ctlr->mii);
|
||||
}
|
||||
wr(ctlr, ENET_EIR, e);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -450,13 +463,11 @@ linkproc(void *arg)
|
|||
Ether *edev = arg;
|
||||
Ctlr *ctlr = edev->ctlr;
|
||||
MiiPhy *phy;
|
||||
int link = -1;
|
||||
int link = 0;
|
||||
|
||||
while(waserror())
|
||||
;
|
||||
|
||||
miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
|
||||
|
||||
miiane(ctlr->mii, ~0, ~0, ~0);
|
||||
for(;;){
|
||||
miistatus(ctlr->mii);
|
||||
phy = ctlr->mii->curphy;
|
||||
|
@ -505,7 +516,7 @@ linkproc(void *arg)
|
|||
edev->mbps = phy->speed;
|
||||
|
||||
wr(ctlr, ENET_RDAR, RDAR_ACTIVE);
|
||||
}
|
||||
}
|
||||
edev->link = link;
|
||||
print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
|
||||
}
|
||||
|
@ -532,7 +543,7 @@ attach(Ether *edev)
|
|||
wr(ctlr, ENET_RCR, RCR_MII_MODE | RCR_RGMII_EN | Maxtu<<RCR_MAX_FL_SHIFT);
|
||||
|
||||
/* set MII clock to 2.5Mhz, 10ns hold time */
|
||||
wr(ctlr, ENET_MSCR, ((Moduleclk/(2*2500000))-1)<<MSCR_SPEED_SHIFT | ((Moduleclk/10000000)-1)<<MSCR_HOLD_SHIFT);
|
||||
wr(ctlr, ENET_MSCR, ((Busclk/(2*2500000))-1)<<MSCR_SPEED_SHIFT | ((Busclk/1000000)-1)<<MSCR_HOLD_SHIFT);
|
||||
|
||||
ctlr->intmask |= INT_MII;
|
||||
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
||||
|
@ -586,8 +597,8 @@ attach(Ether *edev)
|
|||
wr(ctlr, ENET_TFWR, TFWR_STRFWD);
|
||||
|
||||
/* interrupt coalescing: 200 pkts, 1000 µs */
|
||||
wr(ctlr, ENET_RXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Moduleclk)/64000000)<<IC_TT_SHIFT);
|
||||
wr(ctlr, ENET_TXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Moduleclk)/64000000)<<IC_TT_SHIFT);
|
||||
wr(ctlr, ENET_RXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Txclk)/64000000)<<IC_TT_SHIFT);
|
||||
wr(ctlr, ENET_TXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Txclk)/64000000)<<IC_TT_SHIFT);
|
||||
|
||||
ctlr->intmask |= INT_TXF | INT_RXF;
|
||||
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
||||
|
@ -688,6 +699,33 @@ pnp(Ether *edev)
|
|||
edev->mbps = 1000;
|
||||
edev->maxmtu = Maxtu;
|
||||
|
||||
iomuxpad("pad_enet_mdc", "enet1_mdc", "~LVTTL ~HYS ~PUE ~ODE SLOW 75_OHM");
|
||||
iomuxpad("pad_enet_mdio", "enet1_mdio", "~LVTTL ~HYS ~PUE ODE SLOW 75_OHM");
|
||||
|
||||
iomuxpad("pad_enet_td3", "enet1_rgmii_td3", "~LVTTL ~HYS ~PUE ~ODE MAX 40_OHM");
|
||||
iomuxpad("pad_enet_td2", "enet1_rgmii_td2", "~LVTTL ~HYS ~PUE ~ODE MAX 40_OHM");
|
||||
iomuxpad("pad_enet_td1", "enet1_rgmii_td1", "~LVTTL ~HYS ~PUE ~ODE MAX 40_OHM");
|
||||
iomuxpad("pad_enet_td0", "enet1_rgmii_td0", "~LVTTL ~HYS ~PUE ~ODE MAX 40_OHM");
|
||||
iomuxpad("pad_enet_tx_ctl", "enet1_rgmii_tx_ctl", "~LVTTL ~HYS ~PUE ~ODE MAX 40_OHM VSEL_0");
|
||||
iomuxpad("pad_enet_txc", "enet1_rgmii_txc", "~LVTTL ~HYS ~PUE ~ODE MAX 40_OHM");
|
||||
|
||||
iomuxpad("pad_enet_rxc", "enet1_rgmii_rxc", "~LVTTL HYS ~PUE ~ODE FAST 255_OHM");
|
||||
iomuxpad("pad_enet_rx_ctl", "enet1_rgmii_rx_ctl", "~LVTTL HYS ~PUE ~ODE FAST 255_OHM");
|
||||
iomuxpad("pad_enet_rd0", "enet1_rgmii_rd0", "~LVTTL HYS ~PUE ~ODE FAST 255_OHM");
|
||||
iomuxpad("pad_enet_rd1", "enet1_rgmii_rd1", "~LVTTL HYS ~PUE ~ODE FAST 255_OHM");
|
||||
iomuxpad("pad_enet_rd2", "enet1_rgmii_rd2", "~LVTTL HYS ~PUE ~ODE FAST 255_OHM");
|
||||
iomuxpad("pad_enet_rd3", "enet1_rgmii_rd3", "~LVTTL HYS ~PUE ~ODE FAST 255_OHM");
|
||||
|
||||
setclkgate("enet1.ipp_ind_mac0_txclk", 0);
|
||||
setclkgate("sim_enet.mainclk", 0);
|
||||
|
||||
setclkrate("enet1.ipg_clk", "system_pll1_div3", Busclk);
|
||||
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Txclk);
|
||||
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", Ptpclk);
|
||||
|
||||
setclkgate("enet1.ipp_ind_mac0_txclk", 1);
|
||||
setclkgate("sim_enet.mainclk", 1);
|
||||
|
||||
if(reset(edev) < 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ extern void meminit(void);
|
|||
extern void putasid(Proc*);
|
||||
|
||||
extern void* ucalloc(usize);
|
||||
extern void* fbmemalloc(usize);
|
||||
|
||||
/* clock */
|
||||
extern void clockinit(void);
|
||||
|
@ -138,3 +139,23 @@ extern void writeconf(void);
|
|||
|
||||
extern int isaconfig(char*, int, ISAConf*);
|
||||
extern void links(void);
|
||||
|
||||
/* ccm */
|
||||
extern void setclkgate(char *name, int on);
|
||||
extern void setclkrate(char *name, char *source, int freq);
|
||||
extern int getclkrate(char *name);
|
||||
|
||||
/* gpc */
|
||||
extern void powerup(char *dom);
|
||||
|
||||
/* lcd */
|
||||
extern void lcdinit(void);
|
||||
|
||||
/* iomux */
|
||||
extern void iomuxpad(char *pads, char *sel, char *cfg);
|
||||
extern uint iomuxgpr(int gpr, uint set, uint mask);
|
||||
|
||||
/* gpio */
|
||||
#define GPIO_PIN(n, m) ((n)<<5 | (m))
|
||||
extern void gpioout(uint pin, int set);
|
||||
extern int gpioin(uint pin);
|
||||
|
|
63
sys/src/9/imx8/gpc.c
Normal file
63
sys/src/9/imx8/gpc.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
|
||||
/* power gating controller registers */
|
||||
enum {
|
||||
GPC_PGC_CPU_0_1_MAPPING = 0xEC/4,
|
||||
GPC_PGC_PU_PGC_SW_PUP_REQ = 0xF8/4,
|
||||
GPC_PGC_PU_PGC_SW_PDN_REQ = 0x104/4,
|
||||
};
|
||||
|
||||
static u32int *gpc = (u32int*)(VIRTIO + 0x3A0000);
|
||||
|
||||
typedef struct Tab Tab;
|
||||
struct Tab {
|
||||
char *dom;
|
||||
uint mask;
|
||||
};
|
||||
|
||||
static Tab pu_tab[] = {
|
||||
"mipi", 1<<0,
|
||||
"pcie", 1<<1,
|
||||
"usb_otg1", 1<<2,
|
||||
"usb_otg2", 1<<3,
|
||||
"ddr1", 1<<5,
|
||||
"ddr2", 1<<6,
|
||||
"gpu", 1<<7,
|
||||
"vpu", 1<<8,
|
||||
"hdmi", 1<<9,
|
||||
"disp", 1<<10,
|
||||
"mipi_csi1", 1<<11,
|
||||
"mipi_csi2", 1<<12,
|
||||
"pcie2", 1<<13,
|
||||
|
||||
nil,
|
||||
};
|
||||
|
||||
void
|
||||
powerup(char *dom)
|
||||
{
|
||||
Tab *t;
|
||||
|
||||
if(dom == nil)
|
||||
return;
|
||||
|
||||
for(t = pu_tab; t->dom != nil; t++)
|
||||
if(cistrcmp(dom, t->dom) == 0)
|
||||
goto Found;
|
||||
|
||||
panic("powerup: domain %s not defined", dom);
|
||||
|
||||
Found:
|
||||
gpc[GPC_PGC_CPU_0_1_MAPPING] = 0x0000FFFF;
|
||||
|
||||
gpc[GPC_PGC_PU_PGC_SW_PUP_REQ] |= t->mask;
|
||||
while(gpc[GPC_PGC_PU_PGC_SW_PUP_REQ] & t->mask)
|
||||
;
|
||||
|
||||
gpc[GPC_PGC_CPU_0_1_MAPPING] = 0;
|
||||
}
|
82
sys/src/9/imx8/gpio.c
Normal file
82
sys/src/9/imx8/gpio.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "../port/error.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
|
||||
/* gpio registers */
|
||||
enum {
|
||||
GPIO_DR = 0x00/4,
|
||||
GPIO_GDIR = 0x04/4,
|
||||
GPIO_PSR = 0x08/4,
|
||||
GPIO_ICR1 = 0x0C/4,
|
||||
GPIO_ICR2 = 0x10/4,
|
||||
GPIO_IMR = 0x14/4,
|
||||
GPIO_ISR = 0x18/4,
|
||||
GPIO_EDGE_SEL = 0x1C/4,
|
||||
};
|
||||
|
||||
typedef struct Ctlr Ctlr;
|
||||
struct Ctlr
|
||||
{
|
||||
u32int *reg;
|
||||
char *clk;
|
||||
u32int dir;
|
||||
int enabled;
|
||||
};
|
||||
|
||||
static Ctlr ctlrs[5] = {
|
||||
{(u32int*)(VIRTIO + 0x200000), "gpio1.ipg_clk_s" },
|
||||
{(u32int*)(VIRTIO + 0x210000), "gpio2.ipg_clk_s" },
|
||||
{(u32int*)(VIRTIO + 0x220000), "gpio3.ipg_clk_s" },
|
||||
{(u32int*)(VIRTIO + 0x230000), "gpio4.ipg_clk_s" },
|
||||
{(u32int*)(VIRTIO + 0x240000), "gpio5.ipg_clk_s" },
|
||||
};
|
||||
|
||||
static Ctlr*
|
||||
enable(uint pin)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
|
||||
pin /= 32;
|
||||
if(pin < 1 || pin > nelem(ctlrs))
|
||||
return nil;
|
||||
|
||||
ctlr = &ctlrs[pin-1];
|
||||
if(!ctlr->enabled){
|
||||
setclkgate(ctlr->clk, 1);
|
||||
ctlr->reg[GPIO_IMR] = 0;
|
||||
ctlr->dir = ctlr->reg[GPIO_GDIR];
|
||||
ctlr->enabled = 1;
|
||||
}
|
||||
return ctlr;
|
||||
}
|
||||
|
||||
void
|
||||
gpioout(uint pin, int set)
|
||||
{
|
||||
u32int bit = 1 << (pin % 32);
|
||||
Ctlr *ctlr = enable(pin);
|
||||
if(ctlr == nil)
|
||||
return;
|
||||
if((ctlr->dir & bit) == 0)
|
||||
ctlr->reg[GPIO_GDIR] = ctlr->dir |= bit;
|
||||
if(set)
|
||||
ctlr->reg[GPIO_DR] |= bit;
|
||||
else
|
||||
ctlr->reg[GPIO_DR] &= ~bit;
|
||||
}
|
||||
|
||||
int
|
||||
gpioin(uint pin)
|
||||
{
|
||||
u32int bit = 1 << (pin % 32);
|
||||
Ctlr *ctlr = enable(pin);
|
||||
if(ctlr == nil)
|
||||
return -1;
|
||||
if(ctlr->dir & bit)
|
||||
ctlr->reg[GPIO_GDIR] = ctlr->dir &= ~bit;
|
||||
return (ctlr->reg[GPIO_DR] & bit) != 0;
|
||||
}
|
270
sys/src/9/imx8/i2cimx.c
Normal file
270
sys/src/9/imx8/i2cimx.c
Normal file
|
@ -0,0 +1,270 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "../port/error.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/i2c.h"
|
||||
|
||||
enum {
|
||||
Moduleclk = 25*Mhz,
|
||||
|
||||
I2C_IADR = 0x00,
|
||||
I2C_IFDR = 0x04,
|
||||
I2C_I2CR = 0x08,
|
||||
I2CR_IEN = 1<<7,
|
||||
I2CR_IIEN = 1<<6,
|
||||
I2CR_MSTA = 1<<5,
|
||||
I2CR_MTX = 1<<4,
|
||||
I2CR_TXAK = 1<<3,
|
||||
I2CR_RSTA = 1<<2,
|
||||
I2C_I2SR = 0x0C,
|
||||
I2SR_ICF = 1<<7,
|
||||
I2SR_IAAS = 1<<6,
|
||||
I2SR_IBB = 1<<5,
|
||||
I2SR_IAL = 1<<4,
|
||||
I2SR_SRW = 1<<2,
|
||||
I2SR_IIF = 1<<1,
|
||||
I2SR_RXAK = 1<<0,
|
||||
I2C_I2DR = 0x10,
|
||||
};
|
||||
|
||||
typedef struct Ctlr Ctlr;
|
||||
struct Ctlr
|
||||
{
|
||||
void *regs;
|
||||
int irq;
|
||||
|
||||
Rendez;
|
||||
};
|
||||
|
||||
static void
|
||||
interrupt(Ureg*, void *arg)
|
||||
{
|
||||
I2Cbus *bus = arg;
|
||||
Ctlr *ctlr = bus->ctlr;
|
||||
wakeup(ctlr);
|
||||
}
|
||||
|
||||
static int
|
||||
haveirq(void *arg)
|
||||
{
|
||||
uchar *regs = arg;
|
||||
return regs[I2C_I2SR] & (I2SR_IAL|I2SR_IIF);
|
||||
}
|
||||
|
||||
static int
|
||||
waitsr(Ctlr *ctlr, int inv, int mask)
|
||||
{
|
||||
uchar *regs = ctlr->regs;
|
||||
int sr;
|
||||
|
||||
for(;;){
|
||||
sr = regs[I2C_I2SR];
|
||||
if(sr & I2SR_IAL){
|
||||
regs[I2C_I2SR] = sr & ~(I2SR_IAL|I2SR_IIF);
|
||||
break;
|
||||
}
|
||||
if(sr & I2SR_IIF)
|
||||
regs[I2C_I2SR] = sr & ~I2SR_IIF;
|
||||
if((sr ^ inv) & mask)
|
||||
break;
|
||||
|
||||
/* polling mode */
|
||||
if(up == nil || !islo())
|
||||
continue;
|
||||
|
||||
tsleep(ctlr, haveirq, regs, 1);
|
||||
}
|
||||
return sr ^ inv;
|
||||
}
|
||||
|
||||
static uchar dummy;
|
||||
|
||||
static int
|
||||
io(I2Cbus *bus, uchar *pkt, int olen, int ilen)
|
||||
{
|
||||
Ctlr *ctlr = bus->ctlr;
|
||||
uchar *regs = ctlr->regs;
|
||||
int cr, sr, alen, o, i;
|
||||
|
||||
cr = regs[I2C_I2CR];
|
||||
if((cr & I2CR_IEN) == 0)
|
||||
return -1;
|
||||
|
||||
o = 0;
|
||||
if(olen <= 0)
|
||||
goto Stop;
|
||||
|
||||
alen = 1;
|
||||
if((pkt[0] & 0xF8) == 0xF0 && olen > alen)
|
||||
alen++;
|
||||
|
||||
regs[I2C_IADR] = (pkt[0]&0xFE)^0xFE; /* make sure doesnt match */
|
||||
|
||||
/* wait for bus idle */
|
||||
waitsr(ctlr, I2SR_IBB, I2SR_IBB);
|
||||
|
||||
/* start */
|
||||
cr |= I2CR_MSTA | I2CR_MTX | I2CR_TXAK | I2CR_IIEN;
|
||||
regs[I2C_I2CR] = cr;
|
||||
|
||||
/* wait for bus busy */
|
||||
if(waitsr(ctlr, 0, I2SR_IBB) & I2SR_IAL)
|
||||
goto Err;
|
||||
|
||||
if(olen > alen)
|
||||
pkt[0] &= ~1;
|
||||
|
||||
for(o=0; o<olen; o++){
|
||||
regs[I2C_I2DR] = pkt[o];
|
||||
sr = waitsr(ctlr, 0, I2SR_IIF);
|
||||
if(sr & I2SR_IAL)
|
||||
goto Err;
|
||||
if(sr & I2SR_RXAK)
|
||||
goto Stop;
|
||||
}
|
||||
|
||||
if(ilen <= 0)
|
||||
goto Stop;
|
||||
|
||||
if((pkt[0]&1) == 0){
|
||||
regs[I2C_I2CR] = cr | I2CR_RSTA;
|
||||
|
||||
pkt[0] |= 1;
|
||||
for(i=0; i<alen; i++){
|
||||
regs[I2C_I2DR] = pkt[i];
|
||||
sr = waitsr(ctlr, 0, I2SR_IIF);
|
||||
if(sr & I2SR_IAL)
|
||||
goto Err;
|
||||
if(sr & I2SR_RXAK)
|
||||
goto Stop;
|
||||
}
|
||||
}
|
||||
|
||||
cr &= ~(I2CR_MTX | I2CR_TXAK);
|
||||
if(ilen == 1) cr |= I2CR_TXAK;
|
||||
regs[I2C_I2CR] = cr;
|
||||
dummy = regs[I2C_I2DR]; /* start the next read */
|
||||
|
||||
for(i=1; i<=ilen; i++){
|
||||
sr = waitsr(ctlr, I2SR_ICF, I2SR_IIF);
|
||||
if(sr & I2SR_IAL)
|
||||
goto Err;
|
||||
if(sr & I2SR_ICF)
|
||||
goto Stop;
|
||||
if(i == ilen){
|
||||
cr &= ~(I2CR_MSTA|I2CR_IIEN);
|
||||
regs[I2C_I2CR] = cr;
|
||||
}
|
||||
else if(i == ilen-1){
|
||||
cr |= I2CR_TXAK;
|
||||
regs[I2C_I2CR] = cr;
|
||||
}
|
||||
pkt[o++] = regs[I2C_I2DR];
|
||||
}
|
||||
|
||||
return o;
|
||||
Err:
|
||||
o = -1;
|
||||
Stop:
|
||||
cr &= ~(I2CR_MTX|I2CR_MSTA|I2CR_RSTA|I2CR_IIEN);
|
||||
regs[I2C_I2CR] = cr;
|
||||
return o;
|
||||
}
|
||||
|
||||
static int
|
||||
divindex(int v)
|
||||
{
|
||||
static int tab[] = {
|
||||
/* 0x00 */ 30, 32, 36, 42, 48, 52, 60, 72,
|
||||
/* 0x08 */ 80, 88, 104, 128, 144, 160, 192, 240,
|
||||
/* 0x10 */ 288, 320, 384, 480, 576, 640, 768, 960,
|
||||
/* 0x18 */1152,1280,1536,1920,2304,2560,3072,3840,
|
||||
/* 0x20 */ 22, 24, 26, 28, 32, 36, 40, 44,
|
||||
/* 0x28 */ 48, 56, 64, 72, 80, 96, 112, 128,
|
||||
/* 0x30 */ 160, 192, 224, 256, 320, 384, 448, 512,
|
||||
/* 0x38 */ 640, 768, 896,1024,1280,1536,1792,2048,
|
||||
};
|
||||
int i, x = -1;
|
||||
for(i = 0; i < nelem(tab); i++){
|
||||
if(tab[i] < v)
|
||||
continue;
|
||||
if(x < 0 || tab[i] < tab[x]){
|
||||
x = i;
|
||||
if(tab[i] == v)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static void
|
||||
clkenable(char *name, int on)
|
||||
{
|
||||
char clk[32];
|
||||
|
||||
snprint(clk, sizeof(clk), "%s.ipg_clk_patref", name);
|
||||
setclkgate(clk, 0);
|
||||
if(on) {
|
||||
setclkrate(clk, "osc_25m_ref_clk", Moduleclk);
|
||||
setclkgate(clk, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
init(I2Cbus *bus)
|
||||
{
|
||||
Ctlr *ctlr = bus->ctlr;
|
||||
uchar *regs = ctlr->regs;
|
||||
|
||||
clkenable(bus->name, 1);
|
||||
|
||||
regs[I2C_IFDR] = divindex(Moduleclk / bus->speed);
|
||||
regs[I2C_IADR] = 0;
|
||||
|
||||
regs[I2C_I2CR] = I2CR_IEN;
|
||||
delay(1);
|
||||
|
||||
intrenable(ctlr->irq, interrupt, bus, BUSUNKNOWN, bus->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Ctlr ctlr1 = {
|
||||
.regs = (void*)(VIRTIO + 0xA20000),
|
||||
.irq = IRQi2c1,
|
||||
};
|
||||
static Ctlr ctlr2 = {
|
||||
.regs = (void*)(VIRTIO + 0xA30000),
|
||||
.irq = IRQi2c2,
|
||||
};
|
||||
static Ctlr ctlr3 = {
|
||||
.regs = (void*)(VIRTIO + 0xA40000),
|
||||
.irq = IRQi2c3,
|
||||
};
|
||||
static Ctlr ctlr4 = {
|
||||
.regs = (void*)(VIRTIO + 0xA50000),
|
||||
.irq = IRQi2c4,
|
||||
};
|
||||
|
||||
void
|
||||
i2cimxlink(void)
|
||||
{
|
||||
static I2Cbus i2c1 = { "i2c1", 400000, &ctlr1, init, io };
|
||||
static I2Cbus i2c3 = { "i2c3", 400000, &ctlr3, init, io };
|
||||
static I2Cbus i2c4 = { "i2c4", 400000, &ctlr4, init, io };
|
||||
|
||||
iomuxpad("pad_i2c1_sda", "i2c1_sda", "SION ~LVTTL ~HYS PUE ODE MAX 40_OHM");
|
||||
iomuxpad("pad_i2c1_scl", "i2c1_scl", "SION ~LVTTL ~HYS PUE ODE MAX 40_OHM");
|
||||
addi2cbus(&i2c1);
|
||||
|
||||
iomuxpad("pad_i2c3_sda", "i2c3_sda", "SION ~LVTTL ~HYS PUE ODE MAX 40_OHM");
|
||||
iomuxpad("pad_i2c3_scl", "i2c3_scl", "SION ~LVTTL ~HYS PUE ODE MAX 40_OHM VSEL_0");
|
||||
addi2cbus(&i2c3);
|
||||
|
||||
iomuxpad("pad_i2c4_sda", "i2c4_sda", "SION ~LVTTL ~HYS PUE ODE MAX 40_OHM");
|
||||
iomuxpad("pad_i2c4_scl", "i2c4_scl", "SION ~LVTTL ~HYS PUE ODE MAX 40_OHM");
|
||||
addi2cbus(&i2c4);
|
||||
}
|
|
@ -7,6 +7,9 @@ enum {
|
|||
IRQcntps = PPI+13,
|
||||
IRQcntpns = PPI+14,
|
||||
|
||||
IRQusdhc1 = SPI+22,
|
||||
IRQusdhc2 = SPI+23,
|
||||
|
||||
IRQuart1 = SPI+26,
|
||||
IRQuart2 = SPI+27,
|
||||
IRQuart3 = SPI+28,
|
||||
|
|
1139
sys/src/9/imx8/iomux.c
Normal file
1139
sys/src/9/imx8/iomux.c
Normal file
File diff suppressed because it is too large
Load diff
911
sys/src/9/imx8/lcd.c
Normal file
911
sys/src/9/imx8/lcd.c
Normal file
|
@ -0,0 +1,911 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/i2c.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
|
||||
extern Memimage *gscreen;
|
||||
|
||||
/* system reset controller registers */
|
||||
enum {
|
||||
SRC_MIPIPHY_RCR = 0x28/4,
|
||||
RCR_MIPI_DSI_PCLK_RESET_N = 1<<5,
|
||||
RCR_MIPI_DSI_ESC_RESET_N = 1<<4,
|
||||
RCR_MIPI_DSI_DPI_RESET_N = 1<<3,
|
||||
RCR_MIPI_DSI_RESET_N = 1<<2,
|
||||
RCR_MIPI_DSI_RESET_BYTE_N = 1<<1,
|
||||
|
||||
SRC_DISP_RCR = 0x34/4,
|
||||
};
|
||||
|
||||
/* pwm controller registers */
|
||||
enum {
|
||||
Pwmsrcclk = 25*Mhz,
|
||||
|
||||
PWMCR = 0x00/4,
|
||||
CR_FWM_1 = 0<<26,
|
||||
CR_FWM_2 = 1<<26,
|
||||
CR_FWM_3 = 2<<26,
|
||||
CR_FWM_4 = 3<<26,
|
||||
|
||||
CR_STOPEN = 1<<25,
|
||||
CR_DOZEN = 1<<24,
|
||||
CR_WAITEN = 1<<23,
|
||||
CR_DBGEN = 1<<22,
|
||||
CR_BCTR = 1<<21,
|
||||
CR_HCTR = 1<<20,
|
||||
|
||||
CR_POUTC = 1<<18,
|
||||
|
||||
CR_CLKSRC_OFF = 0<<16,
|
||||
CR_CLKSRC_IPG = 1<<16,
|
||||
CR_CLKSRC_HIGHFREQ = 2<<16,
|
||||
CR_CLKSRC_32K = 3<<16,
|
||||
|
||||
CR_PRESCALER_SHIFT = 4,
|
||||
|
||||
CR_SWR = 1<<3,
|
||||
|
||||
CR_REPEAT_1 = 0<<1,
|
||||
CR_REPEAT_2 = 1<<1,
|
||||
CR_REPEAT_4 = 2<<1,
|
||||
CR_REPEAT_8 = 3<<1,
|
||||
|
||||
CR_EN = 1<<0,
|
||||
|
||||
PWMSR = 0x04/4,
|
||||
PWMIR = 0x08/4,
|
||||
PWMSAR = 0x0C/4,
|
||||
SAR_MASK = 0xFFFF,
|
||||
PWMPR = 0x10/4,
|
||||
PR_MASK = 0xFFFF,
|
||||
PWMCNR = 0x14/4,
|
||||
CNR_MASK = 0xFFFF,
|
||||
};
|
||||
|
||||
/* dphy registers */
|
||||
enum {
|
||||
DPHY_PD_PHY = 0x0/4,
|
||||
DPHY_M_PRG_HS_PREPARE = 0x4/4,
|
||||
DPHY_MC_PRG_HS_PREPARE = 0x8/4,
|
||||
DPHY_M_PRG_HS_ZERO = 0xc/4,
|
||||
DPHY_MC_PRG_HS_ZERO = 0x10/4,
|
||||
DPHY_M_PRG_HS_TRAIL = 0x14/4,
|
||||
DPHY_MC_PRG_HS_TRAIL = 0x18/4,
|
||||
DPHY_PD_PLL = 0x1c/4,
|
||||
DPHY_TST = 0x20/4,
|
||||
DPHY_CN = 0x24/4,
|
||||
DPHY_CM = 0x28/4,
|
||||
DPHY_CO = 0x2c/4,
|
||||
DPHY_LOCK = 0x30/4,
|
||||
DPHY_LOCK_BYP = 0x34/4,
|
||||
DPHY_RTERM_SEL = 0x38/4,
|
||||
DPHY_AUTO_PD_EN = 0x3c/4,
|
||||
DPHY_RXLPRP = 0x40/4,
|
||||
DPHY_RXCDR = 0x44/4,
|
||||
DPHY_RXHS_SETTLE = 0x48/4, /* undocumented */
|
||||
};
|
||||
|
||||
/* dsi-host registers */
|
||||
enum {
|
||||
DSI_HOST_CFG_NUM_LANES = 0x0/4,
|
||||
DSI_HOST_CFG_NONCONTINUOUS_CLK = 0x4/4,
|
||||
DSI_HOST_CFG_AUTOINSERT_EOTP = 0x14/4,
|
||||
DSI_HOST_CFG_T_PRE = 0x8/4,
|
||||
DSI_HOST_CFG_T_POST = 0xc/4,
|
||||
DSI_HOST_CFG_TX_GAP = 0x10/4,
|
||||
DSI_HOST_CFG_EXTRA_CMDS_AFTER_EOTP = 0x18/4,
|
||||
DSI_HOST_CFG_HTX_TO_COUNT = 0x1c/4,
|
||||
DSI_HOST_CFG_LRX_H_TO_COUNT = 0x20/4,
|
||||
DSI_HOST_CFG_BTA_H_TO_COUNT = 0x24/4,
|
||||
DSI_HOST_CFG_TWAKEUP = 0x28/4,
|
||||
|
||||
DSI_HOST_CFG_DPI_INTERFACE_COLOR_CODING = 0x208/4,
|
||||
DSI_HOST_CFG_DPI_PIXEL_FORMAT = 0x20c/4,
|
||||
DSI_HOST_CFG_DPI_VSYNC_POLARITY = 0x210/4,
|
||||
DSI_HOST_CFG_DPI_HSYNC_POLARITY = 0x214/4,
|
||||
DSI_HOST_CFG_DPI_VIDEO_MODE = 0x218/4,
|
||||
DSI_HOST_CFG_DPI_PIXEL_FIFO_SEND_LEVEL = 0x204/4,
|
||||
DSI_HOST_CFG_DPI_HFP = 0x21c/4,
|
||||
DSI_HOST_CFG_DPI_HBP = 0x220/4,
|
||||
DSI_HOST_CFG_DPI_HSA = 0x224/4,
|
||||
DSI_HOST_CFG_DPI_ENA_BLE_MULT_PKTS = 0x228/4,
|
||||
DSI_HOST_CFG_DPI_BLLP_MODE = 0x234/4,
|
||||
DSI_HOST_CFG_DPI_USE_NULL_PKT_BLLP = 0x238/4,
|
||||
DSI_HOST_CFG_DPI_VC = 0x240/4,
|
||||
DSI_HOST_CFG_DPI_PIXEL_PAYLOAD_SIZE = 0x200/4,
|
||||
DSI_HOST_CFG_DPI_VACTIVE = 0x23c/4,
|
||||
DSI_HOST_CFG_DPI_VBP = 0x22c/4,
|
||||
DSI_HOST_CFG_DPI_VFP = 0x230/4,
|
||||
};
|
||||
|
||||
/* lcdif registers */
|
||||
enum {
|
||||
LCDIF_CTRL = 0x00/4,
|
||||
LCDIF_CTRL_SET = 0x04/4,
|
||||
LCDIF_CTRL_CLR = 0x08/4,
|
||||
LCDIF_CTRL_TOG = 0x0C/4,
|
||||
CTRL_SFTRST = 1<<31,
|
||||
CTRL_CLKGATE = 1<<30,
|
||||
CTRL_YCBCR422_INPUT = 1<<29,
|
||||
CTRL_READ_WEITEB = 1<<28,
|
||||
CTRL_WAIT_FOR_VSYNC_EDGE = 1<<27,
|
||||
CTRL_DATA_SHIFT_DIR = 1<<26,
|
||||
CTRL_SHIFT_NUM_BITS = 0x1F<<21,
|
||||
CTRL_DVI_MODE = 1<<20,
|
||||
CTRL_BYPASS_COUNT = 1<<19,
|
||||
CTRL_VSYNC_MODE = 1<<18,
|
||||
CTRL_DOTCLK_MODE = 1<<17,
|
||||
CTRL_DATA_SELECT = 1<<16,
|
||||
|
||||
CTRL_INPUT_DATA_NO_SWAP = 0<<14,
|
||||
CTRL_INPUT_DATA_LITTLE_ENDIAN = 0<<14,
|
||||
CTRL_INPUT_DATA_BIG_ENDIAB = 1<<14,
|
||||
CTRL_INPUT_DATA_SWAP_ALL_BYTES = 1<<14,
|
||||
CTRL_INPUT_DATA_HWD_SWAP = 2<<14,
|
||||
CTRL_INPUT_DATA_HWD_BYTE_SWAP = 3<<14,
|
||||
|
||||
CTRL_CSC_DATA_NO_SWAP = 0<<12,
|
||||
CTRL_CSC_DATA_LITTLE_ENDIAN = 0<<12,
|
||||
CTRL_CSC_DATA_BIG_ENDIAB = 1<<12,
|
||||
CTRL_CSC_DATA_SWAP_ALL_BYTES = 1<<12,
|
||||
CTRL_CSC_DATA_HWD_SWAP = 2<<12,
|
||||
CTRL_CSC_DATA_HWD_BYTE_SWAP = 3<<12,
|
||||
|
||||
CTRL_LCD_DATABUS_WIDTH_16_BIT = 0<<10,
|
||||
CTRL_LCD_DATABUS_WIDTH_8_BIT = 1<<10,
|
||||
CTRL_LCD_DATABUS_WIDTH_18_BIT = 2<<10,
|
||||
CTRL_LCD_DATABUS_WIDTH_24_BIT = 3<<10,
|
||||
|
||||
CTRL_WORD_LENGTH_16_BIT = 0<<8,
|
||||
CTRL_WORD_LENGTH_8_BIT = 1<<8,
|
||||
CTRL_WORD_LENGTH_18_BIT = 2<<8,
|
||||
CTRL_WORD_LENGTH_24_BIT = 3<<8,
|
||||
|
||||
CTRL_RGB_TO_YCBCR422_CSC = 1<<7,
|
||||
|
||||
CTRL_MASTER = 1<<5,
|
||||
|
||||
CTRL_DATA_FORMAT_16_BIT = 1<<3,
|
||||
CTRL_DATA_FORMAT_18_BIT = 1<<2,
|
||||
CTRL_DATA_FORMAT_24_BIT = 1<<1,
|
||||
|
||||
CTRL_RUN = 1<<0,
|
||||
|
||||
LCDIF_CTRL1 = 0x10/4,
|
||||
LCDIF_CTRL1_SET = 0x14/4,
|
||||
LCDIF_CTRL1_CLR = 0x18/4,
|
||||
LCDIF_CTRL1_TOG = 0x1C/4,
|
||||
CTRL1_COMBINE_MPU_WR_STRB = 1<<27,
|
||||
CTRL1_BM_ERROR_IRQ_EN = 1<<26,
|
||||
CTRL1_BM_ERROR_IRQ = 1<<25,
|
||||
CTRL1_RECOVER_ON_UNDERFLOW = 1<<24,
|
||||
|
||||
CTRL1_INTERLACE_FIELDS = 1<<23,
|
||||
CTRL1_START_INTERLACE_FROM_SECOND_FIELD = 1<<22,
|
||||
|
||||
CTRL1_FIFO_CLEAR = 1<<21,
|
||||
CTRL1_IRQ_ON_ALTERNATE_FIELDS = 1<<20,
|
||||
|
||||
CTRL1_BYTE_PACKING_FORMAT = 0xF<<16,
|
||||
|
||||
CTRL1_OVERFLOW_IRQ_EN = 1<<15,
|
||||
CTRL1_UNDERFLOW_IRQ_EN = 1<<14,
|
||||
CTRL1_CUR_FRAME_DONE_IRQ_EN = 1<<13,
|
||||
CTRL1_VSYNC_EDGE_IRQ_EN = 1<<12,
|
||||
CTRL1_OVERFLOW_IRQ = 1<<11,
|
||||
CTRL1_UNDERFLOW_IRQ = 1<<10,
|
||||
CTRL1_CUR_FRAME_DONE_IRQ = 1<<9,
|
||||
CTRL1_VSYNC_EDGE_IRQ = 1<<8,
|
||||
|
||||
CTRL1_BUSY_ENABLE = 1<<2,
|
||||
CTRL1_MODE86 = 1<<1,
|
||||
CTRL1_RESET = 1<<0,
|
||||
|
||||
LCDIF_CTRL2 = 0x20/4,
|
||||
LCDIF_CTRL2_SET = 0x24/4,
|
||||
LCDIF_CTRL2_CLR = 0x28/4,
|
||||
LCDIF_CTRL2_TOG = 0x2C/4,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_1 = 0<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_2 = 1<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_4 = 2<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_8 = 3<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_16 = 4<<21,
|
||||
|
||||
CTRL2_BURST_LEN_8 = 1<<20,
|
||||
|
||||
CTRL2_ODD_LINE_PATTERN_RGB = 0<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_RBG = 1<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_GBR = 2<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_GRB = 3<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_BRG = 4<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_BGR = 5<<16,
|
||||
|
||||
CTRL2_EVEN_LINE_PATTERN_RGB = 0<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_RBG = 1<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_GBR = 2<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_GRB = 3<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_BRG = 4<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_BGR = 5<<12,
|
||||
|
||||
CTRL2_READ_PACK_DIR = 1<<10,
|
||||
|
||||
CTRL2_READ_MODE_OUTPUT_IN_RGB_FORMAT = 1<<9,
|
||||
CTRL2_READ_MODE_6_BIT_INPUT = 1<<8,
|
||||
CTRL2_READ_MODE_NUM_PACKED_SUBWORDS = 7<<4,
|
||||
CTRL2_INITIAL_DUMMY_READS = 7<<1,
|
||||
|
||||
LCDIF_TRANSFER_COUNT= 0x30/4,
|
||||
TRANSFER_COUNT_V_COUNT = 0xFFFF<<16,
|
||||
TRANSFER_COUNT_H_COUNT = 0xFFFF,
|
||||
|
||||
LCDIF_CUR_BUF = 0x40/4,
|
||||
LCDIF_NEXT_BUF = 0x50/4,
|
||||
|
||||
LCDIF_TIMING = 0x60/4,
|
||||
TIMING_CMD_HOLD = 0xFF<<24,
|
||||
TIMING_CMD_SETUP = 0xFF<<16,
|
||||
TIMING_DATA_HOLD = 0xFF<<8,
|
||||
TIMING_DATA_SETUP = 0xFF<<0,
|
||||
|
||||
LCDIF_VDCTRL0 = 0x70/4,
|
||||
VDCTRL0_VSYNC_OEB = 1<<29,
|
||||
VDCTRL0_ENABLE_PRESENT = 1<<28,
|
||||
|
||||
VDCTRL0_VSYNC_POL = 1<<27,
|
||||
VDCTRL0_HSYNC_POL = 1<<26,
|
||||
VDCTRL0_DOTCLK_POL = 1<<25,
|
||||
VDCTRL0_ENABLE_POL = 1<<24,
|
||||
|
||||
VDCTRL0_VSYNC_PERIOD_UNIT = 1<<21,
|
||||
VDCTRL0_VSYNC_PULSE_WIDTH_UNIT = 1<<20,
|
||||
VDCTRL0_HALF_LINE = 1<<19,
|
||||
VDCTRL0_HALF_LINE_MODE = 1<<18,
|
||||
|
||||
VDCTRL0_VSYNC_PULSE_WIDTH = 0x3FFFF,
|
||||
|
||||
LCDIF_VDCTRL1 = 0x80/4,
|
||||
VDCTRL1_VSYNC_PERIOD = 0xFFFFFFFF,
|
||||
|
||||
LCDIF_VDCTRL2 = 0x90/4,
|
||||
VDCTRL2_HSYNC_PERIOD = 0x3FFFF,
|
||||
VDCTRL2_HSYNC_PULSE_WIDTH = 0x3FFF<<18,
|
||||
|
||||
LCDIF_VDCTRL3 = 0xA0/4,
|
||||
VDCTRL3_VERTICAL_WAIT_CNT = 0xFFFF,
|
||||
VDCTRL3_HORIZONTAL_WAIT_CNT = 0xFFF<<16,
|
||||
VDCTRL3_VSYNC_ONLY = 1<<28,
|
||||
VDCTRL3_MUX_SYNC_SIGNALS = 1<<29,
|
||||
|
||||
LCDIF_VDCTRL4 = 0xB0/4,
|
||||
VDCTRL4_DOTCLK_H_VALID_DATA_CNT = 0x3FFFF,
|
||||
VDCTRL4_SYNC_SIGNALS_ON = 1<<18,
|
||||
|
||||
VDCTRL4_DOTCLK_DLY_2NS = 0<<29,
|
||||
VDCTRL4_DOTCLK_DLY_4NS = 1<<29,
|
||||
VDCTRL4_DOTCLK_DLY_6NS = 2<<29,
|
||||
VDCTRL4_DOTCLK_DLY_8NS = 3<<29,
|
||||
|
||||
LCDIF_DATA = 0x180/4,
|
||||
|
||||
LCDIF_STAT = 0x1B0/4,
|
||||
|
||||
LCDIF_AS_CTRL = 0x210/4,
|
||||
};
|
||||
|
||||
struct video_mode {
|
||||
int pixclk;
|
||||
int hactive;
|
||||
int vactive;
|
||||
int hblank;
|
||||
int vblank;
|
||||
int hso;
|
||||
int vso;
|
||||
int hspw;
|
||||
int vspw;
|
||||
|
||||
char vsync_pol;
|
||||
char hsync_pol;
|
||||
};
|
||||
|
||||
struct dsi_cfg {
|
||||
int lanes;
|
||||
|
||||
int ref_clk;
|
||||
int hs_clk;
|
||||
int ui_ps;
|
||||
|
||||
int byte_clk;
|
||||
int byte_t_ps;
|
||||
|
||||
int tx_esc_clk;
|
||||
int tx_esc_t_ps;
|
||||
|
||||
int rx_esc_clk;
|
||||
|
||||
int clk_pre_ps;
|
||||
int clk_prepare_ps;
|
||||
int clk_zero_ps;
|
||||
|
||||
int hs_prepare_ps;
|
||||
int hs_zero_ps;
|
||||
int hs_trail_ps;
|
||||
int hs_exit_ps;
|
||||
|
||||
int lpx_ps;
|
||||
|
||||
vlong wakeup_ps;
|
||||
};
|
||||
|
||||
/* base addresses, VIRTIO is at 0x30000000 physical */
|
||||
|
||||
static u32int *pwm2 = (u32int*)(VIRTIO + 0x670000);
|
||||
|
||||
static u32int *resetc= (u32int*)(VIRTIO + 0x390000);
|
||||
|
||||
static u32int *dsi = (u32int*)(VIRTIO + 0xA00000);
|
||||
static u32int *dphy = (u32int*)(VIRTIO + 0xA00300);
|
||||
|
||||
static u32int *lcdif = (u32int*)(VIRTIO + 0x320000);
|
||||
|
||||
/* shift and mask */
|
||||
static u32int
|
||||
sm(u32int v, u32int m)
|
||||
{
|
||||
int s;
|
||||
|
||||
if(m == 0)
|
||||
return 0;
|
||||
|
||||
s = 0;
|
||||
while((m & 1) == 0){
|
||||
m >>= 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
return (v & m) << s;
|
||||
}
|
||||
|
||||
static u32int
|
||||
rr(u32int *base, int reg)
|
||||
{
|
||||
u32int val = base[reg];
|
||||
// iprint("%#p+%#.4x -> %#.8ux\n", PADDR(base), reg*4, val);
|
||||
return val;
|
||||
}
|
||||
static void
|
||||
wr(u32int *base, int reg, u32int val)
|
||||
{
|
||||
// iprint("%#p+%#.4x <- %#.8ux\n", PADDR(base), reg*4, val);
|
||||
base[reg] = val;
|
||||
}
|
||||
static void
|
||||
mr(u32int *base, int reg, u32int val, u32int mask)
|
||||
{
|
||||
wr(base, reg, (rr(base, reg) & ~mask) | (val & mask));
|
||||
}
|
||||
|
||||
static void
|
||||
dsiparams(struct dsi_cfg *cfg, int lanes, int hs_clk, int ref_clk, int tx_esc_clk, int rx_esc_clk)
|
||||
{
|
||||
cfg->lanes = lanes;
|
||||
cfg->ref_clk = ref_clk;
|
||||
|
||||
cfg->hs_clk = hs_clk;
|
||||
cfg->ui_ps = (1000000000000LL + (cfg->hs_clk-1)) / cfg->hs_clk;
|
||||
|
||||
cfg->byte_clk = cfg->hs_clk / 8;
|
||||
cfg->byte_t_ps = cfg->ui_ps * 8;
|
||||
|
||||
cfg->tx_esc_clk = tx_esc_clk;
|
||||
cfg->tx_esc_t_ps = (1000000000000LL + (cfg->tx_esc_clk-1)) / cfg->tx_esc_clk;
|
||||
|
||||
cfg->rx_esc_clk = rx_esc_clk;
|
||||
|
||||
/* min 8*ui */
|
||||
cfg->clk_pre_ps = 8*cfg->ui_ps;
|
||||
|
||||
/* min 38ns, max 95ns */
|
||||
cfg->clk_prepare_ps = 38*1000;
|
||||
|
||||
/* clk_prepare + clk_zero >= 300ns */
|
||||
cfg->clk_zero_ps = 300*1000 - cfg->clk_prepare_ps;
|
||||
|
||||
/* min 40ns + 4*ui, max 85ns + 6*ui */
|
||||
cfg->hs_prepare_ps = 40*1000 + 4*cfg->ui_ps;
|
||||
|
||||
/* hs_prepae + hs_zero >= 145ns + 10*ui */
|
||||
cfg->hs_zero_ps = (145*1000 + 10*cfg->ui_ps) - cfg->hs_prepare_ps;
|
||||
|
||||
/* min max(n*8*ui, 60ns + n*4*ui); n=1 */
|
||||
cfg->hs_trail_ps = 60*1000 + 1*4*cfg->ui_ps;
|
||||
if(cfg->hs_trail_ps < 1*8*cfg->ui_ps)
|
||||
cfg->hs_trail_ps = 1*8*cfg->ui_ps;
|
||||
|
||||
/* min 100ns */
|
||||
cfg->hs_exit_ps = 100*1000;
|
||||
|
||||
/* min 50ns */
|
||||
cfg->lpx_ps = 50*1000;
|
||||
|
||||
/* min 1ms */
|
||||
cfg->wakeup_ps = 1000000000000LL;
|
||||
}
|
||||
|
||||
static void
|
||||
lcdifinit(struct video_mode *mode)
|
||||
{
|
||||
wr(lcdif, LCDIF_CTRL_CLR, CTRL_SFTRST);
|
||||
while(rr(lcdif, LCDIF_CTRL) & CTRL_SFTRST)
|
||||
;
|
||||
wr(lcdif, LCDIF_CTRL_CLR, CTRL_CLKGATE);
|
||||
while(rr(lcdif, LCDIF_CTRL) & (CTRL_SFTRST|CTRL_CLKGATE))
|
||||
;
|
||||
|
||||
wr(lcdif, LCDIF_CTRL1_SET, CTRL1_FIFO_CLEAR);
|
||||
wr(lcdif, LCDIF_AS_CTRL, 0);
|
||||
|
||||
wr(lcdif, LCDIF_CTRL1, sm(7, CTRL1_BYTE_PACKING_FORMAT));
|
||||
|
||||
wr(lcdif, LCDIF_CTRL,
|
||||
CTRL_BYPASS_COUNT |
|
||||
CTRL_MASTER |
|
||||
CTRL_LCD_DATABUS_WIDTH_24_BIT |
|
||||
CTRL_WORD_LENGTH_24_BIT);
|
||||
|
||||
wr(lcdif, LCDIF_TRANSFER_COUNT,
|
||||
sm(mode->vactive, TRANSFER_COUNT_V_COUNT) |
|
||||
sm(mode->hactive, TRANSFER_COUNT_H_COUNT));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL0,
|
||||
VDCTRL0_ENABLE_PRESENT |
|
||||
VDCTRL0_VSYNC_POL | VDCTRL0_HSYNC_POL |
|
||||
VDCTRL0_VSYNC_PERIOD_UNIT |
|
||||
VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
|
||||
sm(mode->vspw, VDCTRL0_VSYNC_PULSE_WIDTH));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL1,
|
||||
sm(mode->vactive + mode->vblank, VDCTRL1_VSYNC_PERIOD));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL2,
|
||||
sm(mode->hactive + mode->hblank, VDCTRL2_HSYNC_PERIOD) |
|
||||
sm(mode->hspw, VDCTRL2_HSYNC_PULSE_WIDTH));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL3,
|
||||
sm(mode->vblank - mode->vso, VDCTRL3_VERTICAL_WAIT_CNT) |
|
||||
sm(mode->hblank - mode->hso, VDCTRL3_HORIZONTAL_WAIT_CNT));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL4,
|
||||
sm(mode->hactive, VDCTRL4_DOTCLK_H_VALID_DATA_CNT));
|
||||
|
||||
wr(lcdif, LCDIF_CUR_BUF, PADDR(gscreen->data->bdata));
|
||||
wr(lcdif, LCDIF_NEXT_BUF, PADDR(gscreen->data->bdata));
|
||||
|
||||
wr(lcdif, LCDIF_CTRL_SET, CTRL_DOTCLK_MODE);
|
||||
|
||||
mr(lcdif, LCDIF_VDCTRL4, VDCTRL4_SYNC_SIGNALS_ON, VDCTRL4_SYNC_SIGNALS_ON);
|
||||
|
||||
wr(lcdif, LCDIF_CTRL_SET, CTRL_RUN);
|
||||
}
|
||||
|
||||
static void
|
||||
bridgeinit(I2Cdev *dev, struct video_mode *mode, struct dsi_cfg *cfg)
|
||||
{
|
||||
int n;
|
||||
|
||||
// clock derived from dsi clock
|
||||
switch(cfg->hs_clk/2000000){
|
||||
case 384:
|
||||
default: n = 1 << 1; break;
|
||||
case 416: n = 2 << 1; break;
|
||||
case 468: n = 0 << 1; break;
|
||||
case 486: n = 3 << 1; break;
|
||||
case 461: n = 4 << 1; break;
|
||||
}
|
||||
i2cwritebyte(dev, 0x0a, n);
|
||||
|
||||
// single channel A
|
||||
n = 1<<5 | (cfg->lanes-4)<<3 | 3<<1;
|
||||
i2cwritebyte(dev, 0x10, n);
|
||||
|
||||
// Enhanced framing and ASSR
|
||||
i2cwritebyte(dev, 0x5a, 0x05);
|
||||
|
||||
// 2 DP lanes w/o SSC
|
||||
i2cwritebyte(dev, 0x93, 0x20);
|
||||
|
||||
// 2.7Gbps DP data rate
|
||||
i2cwritebyte(dev, 0x94, 0x80);
|
||||
|
||||
// Enable PLL and confirm PLL is locked
|
||||
i2cwritebyte(dev, 0x0d, 0x01);
|
||||
|
||||
// wait for PLL to lock
|
||||
while((i2creadbyte(dev, 0x0a) & 0x80) == 0)
|
||||
;
|
||||
|
||||
// Enable ASSR on display
|
||||
i2cwritebyte(dev, 0x64, 0x01);
|
||||
i2cwritebyte(dev, 0x75, 0x01);
|
||||
i2cwritebyte(dev, 0x76, 0x0a);
|
||||
i2cwritebyte(dev, 0x77, 0x01);
|
||||
i2cwritebyte(dev, 0x78, 0x81);
|
||||
|
||||
// Train link and confirm trained
|
||||
i2cwritebyte(dev, 0x96, 0x0a);
|
||||
while(i2creadbyte(dev, 0x96) != 1)
|
||||
;
|
||||
|
||||
// video timings
|
||||
i2cwritebyte(dev, 0x20, mode->hactive & 0xFF);
|
||||
i2cwritebyte(dev, 0x21, mode->hactive >> 8);
|
||||
i2cwritebyte(dev, 0x24, mode->vactive & 0xFF);
|
||||
i2cwritebyte(dev, 0x25, mode->vactive >> 8);
|
||||
i2cwritebyte(dev, 0x2c, mode->hspw);
|
||||
i2cwritebyte(dev, 0x2d, mode->hspw>>8 | (mode->hsync_pol=='-')<<7);
|
||||
i2cwritebyte(dev, 0x30, mode->vspw);
|
||||
i2cwritebyte(dev, 0x31, mode->vspw>>8 | (mode->vsync_pol=='-')<<7);
|
||||
i2cwritebyte(dev, 0x34, mode->hblank - mode->hspw - mode->hso);
|
||||
i2cwritebyte(dev, 0x36, mode->vblank - mode->vspw - mode->vso);
|
||||
i2cwritebyte(dev, 0x38, mode->hso);
|
||||
i2cwritebyte(dev, 0x3a, mode->vso);
|
||||
|
||||
// Enable video stream, ASSR, enhanced framing
|
||||
i2cwritebyte(dev, 0x5a, 0x0d);
|
||||
}
|
||||
|
||||
static char*
|
||||
parseedid128(struct video_mode *mode, uchar edid[128])
|
||||
{
|
||||
static uchar magic[8] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
uchar *p, sum;
|
||||
int i;
|
||||
|
||||
if(memcmp(edid, magic, 8) != 0)
|
||||
return "bad edid magic";
|
||||
|
||||
sum = 0;
|
||||
for(i=0; i<128; i++)
|
||||
sum += edid[i];
|
||||
if(sum != 0)
|
||||
return "bad edid checksum";
|
||||
|
||||
/*
|
||||
* Detailed Timings
|
||||
*/
|
||||
p = edid+8+10+2+5+10+3+16;
|
||||
for(i=0; i<4; i++, p+=18){
|
||||
if((p[0]|p[1])==0)
|
||||
continue;
|
||||
|
||||
memset(mode, 0, sizeof(*mode));
|
||||
|
||||
mode->pixclk = ((p[1]<<8) | p[0]) * 10000;
|
||||
|
||||
mode->hactive = ((p[4] & 0xF0)<<4) | p[2]; /* horizontal active */
|
||||
mode->hblank = ((p[4] & 0x0F)<<8) | p[3]; /* horizontal blanking */
|
||||
mode->vactive = ((p[7] & 0xF0)<<4) | p[5]; /* vertical active */
|
||||
mode->vblank = ((p[7] & 0x0F)<<8) | p[6]; /* vertical blanking */
|
||||
mode->hso = ((p[11] & 0xC0)<<2) | p[8]; /* horizontal sync offset */
|
||||
mode->hspw = ((p[11] & 0x30)<<4) | p[9]; /* horizontal sync pulse width */
|
||||
mode->vso = ((p[11] & 0x0C)<<2) | ((p[10] & 0xF0)>>4); /* vertical sync offset */
|
||||
mode->vspw = ((p[11] & 0x03)<<4) | (p[10] & 0x0F); /* vertical sync pulse width */
|
||||
|
||||
switch((p[17] & 0x18)>>3) {
|
||||
case 3: /* digital separate sync signal; the norm */
|
||||
mode->vsync_pol = (p[17] & 0x04) ? '+' : '-';
|
||||
mode->hsync_pol = (p[17] & 0x02) ? '+' : '-';
|
||||
break;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
return "no edid timings available";
|
||||
}
|
||||
|
||||
static char*
|
||||
getmode(I2Cdev *dev, struct video_mode *mode)
|
||||
{
|
||||
static uchar edid[128];
|
||||
static I2Cdev aux;
|
||||
|
||||
aux.bus = dev->bus;
|
||||
aux.addr = 0x50;
|
||||
aux.subaddr = 1;
|
||||
aux.size = sizeof(edid);
|
||||
|
||||
/* enable passthru mode for address 0x50 (EDID) */
|
||||
i2cwritebyte(dev, 0x60, aux.addr<<1 | 1);
|
||||
addi2cdev(&aux);
|
||||
|
||||
if(i2crecv(&aux, edid, sizeof(edid), 0) != sizeof(edid))
|
||||
return "i2crecv failed to get edid bytes";
|
||||
|
||||
return parseedid128(mode, edid);
|
||||
}
|
||||
|
||||
static void
|
||||
dphyinit(struct dsi_cfg *cfg)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* powerdown */
|
||||
wr(dphy, DPHY_PD_PLL, 1);
|
||||
wr(dphy, DPHY_PD_PHY, 1);
|
||||
|
||||
/* magic */
|
||||
wr(dphy, DPHY_LOCK_BYP, 0);
|
||||
wr(dphy, DPHY_RTERM_SEL, 1);
|
||||
wr(dphy, DPHY_AUTO_PD_EN, 0);
|
||||
wr(dphy, DPHY_RXLPRP, 2);
|
||||
wr(dphy, DPHY_RXCDR, 2);
|
||||
wr(dphy, DPHY_TST, 0x25);
|
||||
|
||||
/* hs timings */
|
||||
n = (2*cfg->hs_prepare_ps - cfg->tx_esc_t_ps) / cfg->tx_esc_t_ps;
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
else if(n > 3)
|
||||
n = 3;
|
||||
wr(dphy, DPHY_M_PRG_HS_PREPARE, n);
|
||||
|
||||
n = (2*cfg->clk_prepare_ps - cfg->tx_esc_t_ps) / cfg->tx_esc_t_ps;
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
else if(n > 1)
|
||||
n = 1;
|
||||
wr(dphy, DPHY_MC_PRG_HS_PREPARE, n);
|
||||
|
||||
n = ((cfg->hs_zero_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps) - 6;
|
||||
if(n < 1)
|
||||
n = 1;
|
||||
wr(dphy, DPHY_M_PRG_HS_ZERO, n);
|
||||
|
||||
n = ((cfg->clk_zero_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps) - 3;
|
||||
if(n < 1)
|
||||
n = 1;
|
||||
wr(dphy, DPHY_MC_PRG_HS_ZERO, n);
|
||||
|
||||
n = (cfg->hs_trail_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps;
|
||||
if(n < 1)
|
||||
n = 1;
|
||||
else if(n > 15)
|
||||
n = 15;
|
||||
wr(dphy, DPHY_M_PRG_HS_TRAIL, n);
|
||||
wr(dphy, DPHY_MC_PRG_HS_TRAIL, n);
|
||||
|
||||
if(cfg->hs_clk < 80*Mhz)
|
||||
n = 0xD;
|
||||
else if(cfg->hs_clk < 90*Mhz)
|
||||
n = 0xC;
|
||||
else if(cfg->hs_clk < 125*Mhz)
|
||||
n = 0xB;
|
||||
else if(cfg->hs_clk < 150*Mhz)
|
||||
n = 0xA;
|
||||
else if(cfg->hs_clk < 225*Mhz)
|
||||
n = 0x9;
|
||||
else if(cfg->hs_clk < 500*Mhz)
|
||||
n = 0x8;
|
||||
else
|
||||
n = 0x7;
|
||||
wr(dphy, DPHY_RXHS_SETTLE, n);
|
||||
|
||||
/* hs_clk = ref_clk * (CM / (CN*CO)); just set CN=CO=1 */
|
||||
n = (cfg->hs_clk + cfg->ref_clk-1) / cfg->ref_clk;
|
||||
|
||||
/* strange encoding for CM */
|
||||
if(n < 32)
|
||||
n = 0xE0 | (n - 16);
|
||||
else if(n < 64)
|
||||
n = 0xC0 | (n - 32);
|
||||
else if(n < 128)
|
||||
n = 0x80 | (n - 64);
|
||||
else
|
||||
n = n - 128;
|
||||
wr(dphy, DPHY_CM, n);
|
||||
|
||||
wr(dphy, DPHY_CN, 0x1F); /* CN==1 */
|
||||
wr(dphy, DPHY_CO, 0x00); /* CO==1 */
|
||||
}
|
||||
|
||||
static void
|
||||
dphypowerup(void)
|
||||
{
|
||||
wr(dphy, DPHY_PD_PLL, 0);
|
||||
while((rr(dphy, DPHY_LOCK) & 1) == 0)
|
||||
;
|
||||
wr(dphy, DPHY_PD_PHY, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
dsiinit(struct dsi_cfg *cfg)
|
||||
{
|
||||
int n;
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_NUM_LANES, cfg->lanes-1);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_NONCONTINUOUS_CLK, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_AUTOINSERT_EOTP, 0x0);
|
||||
|
||||
n = (cfg->clk_pre_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_T_PRE, n);
|
||||
|
||||
n = (cfg->clk_pre_ps + cfg->lpx_ps + cfg->clk_prepare_ps + cfg->clk_zero_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_T_POST, n);
|
||||
|
||||
n = (cfg->hs_exit_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_TX_GAP, n);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_EXTRA_CMDS_AFTER_EOTP, 0x1);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_HTX_TO_COUNT, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_LRX_H_TO_COUNT, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_BTA_H_TO_COUNT, 0x0);
|
||||
|
||||
n = (cfg->wakeup_ps + cfg->tx_esc_t_ps-1) / cfg->tx_esc_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_TWAKEUP, n);
|
||||
}
|
||||
|
||||
static void
|
||||
dpiinit(struct video_mode *mode)
|
||||
{
|
||||
wr(dsi, DSI_HOST_CFG_DPI_INTERFACE_COLOR_CODING, 0x5); // 24-bit
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_PIXEL_FORMAT, 0x3); // 24-bit
|
||||
|
||||
/* this seems wrong */
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VSYNC_POLARITY, 0);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HSYNC_POLARITY, 0);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VIDEO_MODE, 0x1); // non-burst mode with sync events
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_PIXEL_FIFO_SEND_LEVEL, mode->hactive);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HFP, mode->hso);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HBP, mode->hblank - mode->hspw - mode->hso);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HSA, mode->hspw);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_ENA_BLE_MULT_PKTS, 0x0);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_BLLP_MODE, 0x1);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_USE_NULL_PKT_BLLP, 0x0);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VC, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_PIXEL_PAYLOAD_SIZE, mode->hactive);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VACTIVE, mode->vactive - 1);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VBP, mode->vblank - mode->vspw - mode->vso);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VFP, mode->vso);
|
||||
}
|
||||
|
||||
static void
|
||||
backlighton(void)
|
||||
{
|
||||
/* gpio1_io10: for panel backlight enable */
|
||||
iomuxpad("pad_gpio1_io10", "gpio1_io10", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
|
||||
|
||||
/* gpio1_io10 low: panel backlight off */
|
||||
gpioout(GPIO_PIN(1, 10), 0);
|
||||
|
||||
/* pwm2_out: for panel backlight */
|
||||
iomuxpad("pad_spdif_rx", "pwm2_out", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
|
||||
|
||||
setclkrate("pwm2.ipg_clk_high_freq", "osc_25m_ref_clk", Pwmsrcclk);
|
||||
setclkgate("pwm2.ipg_clk_high_freq", 1);
|
||||
|
||||
wr(pwm2, PWMIR, 0);
|
||||
wr(pwm2, PWMCR, CR_STOPEN | CR_DOZEN | CR_WAITEN | CR_DBGEN | CR_CLKSRC_HIGHFREQ | 0<<CR_PRESCALER_SHIFT);
|
||||
wr(pwm2, PWMSAR, Pwmsrcclk/150000);
|
||||
wr(pwm2, PWMPR, (Pwmsrcclk/100000)-2);
|
||||
mr(pwm2, PWMCR, CR_EN, CR_EN);
|
||||
|
||||
/* gpio1_io10 high: panel backlight on */
|
||||
gpioout(GPIO_PIN(1, 10), 1);
|
||||
}
|
||||
|
||||
void
|
||||
lcdinit(void)
|
||||
{
|
||||
struct dsi_cfg dsi_cfg;
|
||||
struct video_mode mode;
|
||||
I2Cdev *bridge;
|
||||
char *err;
|
||||
|
||||
/* GPR13[MIPI_MUX_SEL]: 0 = LCDIF, 1 = DCSS */
|
||||
iomuxgpr(13, 0, 1<<2);
|
||||
|
||||
backlighton();
|
||||
|
||||
/* gpio3_io20: sn65dsi86 bridge enable */
|
||||
iomuxpad("pad_sai5_rxc", "gpio3_io20", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
|
||||
|
||||
/* gpio3_io20 high: bridge on */
|
||||
gpioout(GPIO_PIN(3, 20), 1);
|
||||
|
||||
bridge = i2cdev(i2cbus("i2c4"), 0x2C);
|
||||
if(bridge == nil)
|
||||
return;
|
||||
bridge->subaddr = 1;
|
||||
|
||||
/* power on mipi dsi */
|
||||
powerup("mipi");
|
||||
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_PCLK_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_ESC_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_RESET_BYTE_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_DPI_RESET_N);
|
||||
|
||||
setclkgate("sim_display.mainclk", 0);
|
||||
setclkgate("disp.axi_clk", 0);
|
||||
setclkrate("disp.axi_clk", "system_pll1_clk", 800*Mhz);
|
||||
setclkrate("disp.rtrm_clk", "system_pll1_clk", 400*Mhz);
|
||||
setclkgate("disp.axi_clk", 1);
|
||||
setclkgate("sim_display.mainclk", 1);
|
||||
|
||||
setclkrate("mipi.core", "system_pll1_div3", 266*Mhz);
|
||||
setclkrate("mipi.CLKREF", "system_pll2_clk", 25*Mhz);
|
||||
setclkrate("mipi.RxClkEsc", "system_pll1_clk", 80*Mhz);
|
||||
setclkrate("mipi.TxClkEsc", nil, 20*Mhz);
|
||||
|
||||
/* dsi parameters are fixed for the bridge */
|
||||
dsiparams(&dsi_cfg, 4, 2*486*Mhz,
|
||||
getclkrate("mipi.CLKREF"),
|
||||
getclkrate("mipi.TxClkEsc"),
|
||||
getclkrate("mipi.RxClkEsc"));
|
||||
|
||||
/* release dphy reset */
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_PCLK_RESET_N, RCR_MIPI_DSI_PCLK_RESET_N);
|
||||
|
||||
dphyinit(&dsi_cfg);
|
||||
dsiinit(&dsi_cfg);
|
||||
dphypowerup();
|
||||
|
||||
/* release mipi clock resets (generated by the dphy) */
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_ESC_RESET_N, RCR_MIPI_DSI_ESC_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_RESET_BYTE_N, RCR_MIPI_DSI_RESET_BYTE_N);
|
||||
|
||||
/*
|
||||
* get mode information from EDID, this can only be done after the clocks
|
||||
* are generated by the DPHY and the clock resets have been released.
|
||||
*/
|
||||
err = getmode(bridge, &mode);
|
||||
if(err != nil)
|
||||
goto out;
|
||||
|
||||
/* allocates the framebuffer (gscreen->data->bdata) */
|
||||
if(screeninit(mode.hactive, mode.vactive, 32) < 0){
|
||||
err = "screeninit failed";
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* start the pixel clock. running at the actual pixel clock
|
||||
* causes the screen to shift horizontally after a while.
|
||||
* using 80% seems to fix it - for now.
|
||||
*/
|
||||
setclkrate("lcdif.pix_clk", "system_pll1_clk", (mode.pixclk*8)/10);
|
||||
dpiinit(&mode);
|
||||
|
||||
/* release dpi reset */
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_DPI_RESET_N, RCR_MIPI_DSI_DPI_RESET_N);
|
||||
|
||||
/* enable display port bridge */
|
||||
bridgeinit(bridge, &mode, &dsi_cfg);
|
||||
|
||||
/* send the pixels */
|
||||
lcdifinit(&mode);
|
||||
return;
|
||||
|
||||
out:
|
||||
print("lcdinit: %s\n", err);
|
||||
}
|
|
@ -32,6 +32,7 @@ init0(void)
|
|||
poperror();
|
||||
}
|
||||
kproc("alarm", alarmkproc, 0);
|
||||
|
||||
sp = (char**)(USTKTOP-sizeof(Tos) - 8 - sizeof(sp[0])*4);
|
||||
sp[3] = sp[2] = sp[1] = nil;
|
||||
strcpy(sp[1] = (char*)&sp[4], "boot");
|
||||
|
@ -99,14 +100,7 @@ confinit(void)
|
|||
+ conf.nswap
|
||||
+ conf.nswppo*sizeof(Page*);
|
||||
mainmem->maxsize = kpages;
|
||||
if(!cpuserver)
|
||||
/*
|
||||
* give terminals lots of image memory, too; the dynamic
|
||||
* allocation will balance the load properly, hopefully.
|
||||
* be careful with 32-bit overflow.
|
||||
*/
|
||||
imagmem->maxsize = kpages;
|
||||
|
||||
imagmem->maxsize = kpages;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -149,7 +143,6 @@ main(void)
|
|||
fpuinit();
|
||||
intrinit();
|
||||
clockinit();
|
||||
print("cpu%d: UP!\n", m->machno);
|
||||
synccycles();
|
||||
timersinit();
|
||||
flushtlb();
|
||||
|
@ -175,6 +168,7 @@ main(void)
|
|||
initseg();
|
||||
links();
|
||||
chandevreset();
|
||||
lcdinit();
|
||||
userinit();
|
||||
mpinit();
|
||||
mmu0clear((uintptr*)L1);
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#define STACKALIGN(sp) ((sp) & ~7) /* bug: assure with alloc */
|
||||
#define TRAPFRAMESIZE (38*8)
|
||||
|
||||
/* reserved dram for ucalloc() at the end of KZERO (physical) */
|
||||
/* reserved dram for ucalloc() and fbmemalloc() at the end of KZERO (physical) */
|
||||
#define UCRAMBASE (-KZERO - UCRAMSIZE)
|
||||
#define UCRAMSIZE (1*MiB)
|
||||
#define UCRAMSIZE (8*MiB)
|
||||
|
||||
#define VDRAM (0xFFFFFFFFC0000000ULL) /* 0x40000000 - 0x80000000 */
|
||||
#define KTZERO (VDRAM + 0x100000) /* kernel text start */
|
||||
|
@ -54,7 +54,7 @@
|
|||
#define VMAP (0xFFFFFFFF00000000ULL) /* 0x00000000 - 0x40000000 */
|
||||
|
||||
#define KMAPEND (0xFFFFFFFF00000000ULL) /* 0x140000000 */
|
||||
#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
|
||||
#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
|
||||
|
||||
#define KSEG0 (0xFFFFFFFE00000000ULL)
|
||||
|
||||
|
|
|
@ -58,12 +58,12 @@ OBJ=\
|
|||
# HFILES=
|
||||
|
||||
LIB=\
|
||||
# /$objtype/lib/libmemlayer.a\
|
||||
# /$objtype/lib/libmemdraw.a\
|
||||
# /$objtype/lib/libdraw.a\
|
||||
/$objtype/lib/libmemlayer.a\
|
||||
/$objtype/lib/libmemdraw.a\
|
||||
/$objtype/lib/libdraw.a\
|
||||
/$objtype/lib/libip.a\
|
||||
/$objtype/lib/libsec.a\
|
||||
# /$objtype/lib/libmp.a\
|
||||
/$objtype/lib/libmp.a\
|
||||
/$objtype/lib/libc.a\
|
||||
# /$objtype/lib/libdtracy.a\
|
||||
|
||||
|
@ -80,7 +80,7 @@ $OBJ: $HFILES
|
|||
|
||||
install:V: /$objtype/$p$CONF
|
||||
|
||||
/$objtype/$p$CONF:D: $p$CONF s$p$CONF
|
||||
/$objtype/$p$CONF:D: $p$CONF $p$CONF.u
|
||||
cp -x $p$CONF $p$CONF.u /$objtype/
|
||||
|
||||
<../boot/bootmkfile
|
||||
|
|
|
@ -472,21 +472,36 @@ checkmmu(uintptr, uintptr)
|
|||
{
|
||||
}
|
||||
|
||||
void*
|
||||
ucalloc(usize size)
|
||||
static void*
|
||||
ucramalloc(usize size, uintptr align, uint attr)
|
||||
{
|
||||
static uintptr top = UCRAMBASE + UCRAMSIZE;
|
||||
static Lock lk;
|
||||
uintptr va;
|
||||
|
||||
size = PGROUND(size);
|
||||
uintptr va, pg;
|
||||
|
||||
lock(&lk);
|
||||
top -= size;
|
||||
size += top & align-1;
|
||||
top &= -align;
|
||||
if(top < UCRAMBASE)
|
||||
panic("ucalloc: %p needs %zd bytes\n", getcallerpc(&size), size);
|
||||
panic("ucramalloc: need %zd bytes", size);
|
||||
va = KZERO + top;
|
||||
pg = va & -BY2PG;
|
||||
if(pg != ((va+size) & -BY2PG))
|
||||
mmukmap(pg | attr, pg - KZERO, PGROUND(size));
|
||||
unlock(&lk);
|
||||
|
||||
return (void*)mmukmap(va | PTEUNCACHED, PADDR(va), size);
|
||||
return (void*)va;
|
||||
}
|
||||
|
||||
void*
|
||||
ucalloc(usize size)
|
||||
{
|
||||
return ucramalloc(size, 8, PTEUNCACHED);
|
||||
}
|
||||
|
||||
void*
|
||||
fbmemalloc(usize size)
|
||||
{
|
||||
return ucramalloc(PGROUND(size), BY2PG, PTEWT);
|
||||
}
|
||||
|
|
|
@ -14,14 +14,19 @@ dev
|
|||
fs
|
||||
ether netif
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
|
||||
draw screen swcursor
|
||||
mouse screen swcursor
|
||||
uart
|
||||
usb
|
||||
i2c
|
||||
sd
|
||||
|
||||
link
|
||||
usbxhciimx
|
||||
etherimx ethermii
|
||||
ethermedium
|
||||
loopbackmedium
|
||||
i2cimx devi2c
|
||||
ip
|
||||
tcp
|
||||
udp
|
||||
|
@ -31,8 +36,14 @@ ip
|
|||
icmp6
|
||||
ipmux
|
||||
misc
|
||||
ccm
|
||||
gic
|
||||
gpc
|
||||
gpio
|
||||
lcd
|
||||
uartimx
|
||||
iomux
|
||||
sdmmc usdhc
|
||||
port
|
||||
int cpuserver = 0;
|
||||
bootdir
|
||||
|
|
341
sys/src/9/imx8/screen.c
Normal file
341
sys/src/9/imx8/screen.c
Normal file
|
@ -0,0 +1,341 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
|
||||
enum {
|
||||
Tabstop = 4,
|
||||
Scroll = 8,
|
||||
};
|
||||
|
||||
Memimage *gscreen;
|
||||
|
||||
static Memdata xgdata;
|
||||
static Memimage xgscreen;
|
||||
static Memimage *conscol;
|
||||
static Memimage *back;
|
||||
static Memsubfont *memdefont;
|
||||
|
||||
static Lock screenlock;
|
||||
|
||||
static Point curpos;
|
||||
static int h, w;
|
||||
static Rectangle window;
|
||||
|
||||
static void myscreenputs(char *s, int n);
|
||||
static void screenputc(char *buf);
|
||||
static void screenwin(void);
|
||||
|
||||
enum
|
||||
{
|
||||
CMaccelerated,
|
||||
CMlinear,
|
||||
};
|
||||
|
||||
static Cmdtab mousectlmsg[] =
|
||||
{
|
||||
CMaccelerated, "accelerated", 0,
|
||||
CMlinear, "linear", 1,
|
||||
};
|
||||
|
||||
void
|
||||
mousectl(Cmdbuf *cb)
|
||||
{
|
||||
Cmdtab *ct;
|
||||
|
||||
ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
|
||||
switch(ct->index){
|
||||
case CMaccelerated:
|
||||
mouseaccelerate(cb->nf == 1? 1: atoi(cb->f[1]));
|
||||
break;
|
||||
case CMlinear:
|
||||
mouseaccelerate(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cursoron(void)
|
||||
{
|
||||
swcursorhide(0);
|
||||
swcursordraw(mousexy());
|
||||
}
|
||||
|
||||
void
|
||||
cursoroff(void)
|
||||
{
|
||||
swcursorhide(0);
|
||||
}
|
||||
|
||||
void
|
||||
setcursor(Cursor* curs)
|
||||
{
|
||||
swcursorload(curs);
|
||||
}
|
||||
|
||||
int
|
||||
hwdraw(Memdrawparam *par)
|
||||
{
|
||||
Memimage *dst, *src, *mask;
|
||||
|
||||
if((dst = par->dst) == nil || dst->data == nil)
|
||||
return 0;
|
||||
if((src = par->src) && src->data == nil)
|
||||
src = nil;
|
||||
if((mask = par->mask) && mask->data == nil)
|
||||
mask = nil;
|
||||
|
||||
if(dst->data->bdata == xgdata.bdata)
|
||||
swcursoravoid(par->r);
|
||||
if(src && src->data->bdata == xgdata.bdata)
|
||||
swcursoravoid(par->sr);
|
||||
if(mask && mask->data->bdata == xgdata.bdata)
|
||||
swcursoravoid(par->mr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
screeninit(int width, int height, int depth)
|
||||
{
|
||||
ulong chan;
|
||||
|
||||
switch(depth){
|
||||
default:
|
||||
return -1;
|
||||
case 32:
|
||||
chan = XRGB32;
|
||||
break;
|
||||
case 24:
|
||||
chan = RGB24;
|
||||
break;
|
||||
case 16:
|
||||
chan = RGB16;
|
||||
break;
|
||||
}
|
||||
memsetchan(&xgscreen, chan);
|
||||
xgscreen.r = Rect(0, 0, width, height);
|
||||
xgscreen.clipr = xgscreen.r;
|
||||
xgscreen.depth = depth;
|
||||
xgscreen.width = wordsperline(xgscreen.r, xgscreen.depth);
|
||||
xgdata.bdata = fbmemalloc(xgscreen.width*sizeof(ulong)*height);
|
||||
xgdata.ref = 1;
|
||||
|
||||
xgscreen.data = &xgdata;
|
||||
|
||||
gscreen = &xgscreen;
|
||||
|
||||
conf.monitor = 1;
|
||||
|
||||
memimageinit();
|
||||
memdefont = getmemdefont();
|
||||
screenwin();
|
||||
myscreenputs(kmesg.buf, kmesg.n);
|
||||
screenputs = myscreenputs;
|
||||
swcursorinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
flushmemscreen(Rectangle)
|
||||
{
|
||||
}
|
||||
|
||||
Memdata*
|
||||
attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
|
||||
{
|
||||
if(gscreen == nil)
|
||||
return nil;
|
||||
|
||||
*r = gscreen->r;
|
||||
*d = gscreen->depth;
|
||||
*chan = gscreen->chan;
|
||||
*width = gscreen->width;
|
||||
*softscreen = 0;
|
||||
|
||||
gscreen->data->ref++;
|
||||
return gscreen->data;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
myscreenputs(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)
|
||||
{
|
||||
char *greet;
|
||||
Memimage *orange;
|
||||
Point p, q;
|
||||
Rectangle r;
|
||||
|
||||
back = memblack;
|
||||
conscol = memwhite;
|
||||
|
||||
orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
|
||||
orange->flags |= Frepl;
|
||||
orange->clipr = gscreen->r;
|
||||
orange->data->bdata[0] = 0x40; /* magic: colour? */
|
||||
orange->data->bdata[1] = 0xfd; /* magic: colour? */
|
||||
|
||||
w = memdefont->info[' '].width;
|
||||
h = memdefont->height;
|
||||
|
||||
r = gscreen->r;
|
||||
memimagedraw(gscreen, r, memwhite, ZP, memopaque, ZP, S);
|
||||
window = insetrect(r, 4);
|
||||
memimagedraw(gscreen, window, memblack, 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
|
||||
scroll(void)
|
||||
{
|
||||
int o;
|
||||
Point p;
|
||||
Rectangle r;
|
||||
|
||||
o = Scroll*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;
|
||||
}
|
||||
|
||||
static void
|
||||
screenputc(char *buf)
|
||||
{
|
||||
int w;
|
||||
uint pos;
|
||||
Point p;
|
||||
Rectangle r;
|
||||
static int *xp;
|
||||
static int xbuf[256];
|
||||
|
||||
if (xp < xbuf || xp >= &xbuf[nelem(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 - Tabstop * w)
|
||||
screenputc("\n");
|
||||
|
||||
pos = (curpos.x - window.min.x) / w;
|
||||
pos = Tabstop - pos % Tabstop;
|
||||
*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;
|
||||
break;
|
||||
}
|
||||
}
|
32
sys/src/9/imx8/screen.h
Normal file
32
sys/src/9/imx8/screen.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* devmouse.c */
|
||||
typedef struct Cursor Cursor;
|
||||
extern Cursor cursor;
|
||||
extern void mousetrack(int, int, int, ulong);
|
||||
extern void absmousetrack(int, int, int, ulong);
|
||||
extern Point mousexy(void);
|
||||
extern void mouseaccelerate(int);
|
||||
|
||||
/* screen.c */
|
||||
extern int screeninit(int width, int hight, int depth);
|
||||
extern void blankscreen(int);
|
||||
extern void flushmemscreen(Rectangle);
|
||||
extern Memdata* attachscreen(Rectangle*, ulong*, int*, int*, int*);
|
||||
extern void cursoron(void);
|
||||
extern void cursoroff(void);
|
||||
extern void setcursor(Cursor*);
|
||||
|
||||
extern void mousectl(Cmdbuf*);
|
||||
extern void mouseresize(void);
|
||||
extern void mouseredraw(void);
|
||||
|
||||
/* devdraw.c */
|
||||
extern QLock drawlock;
|
||||
|
||||
#define ishwimage(i) 1 /* for ../port/devdraw.c */
|
||||
|
||||
/* swcursor.c */
|
||||
void swcursorhide(int);
|
||||
void swcursoravoid(Rectangle);
|
||||
void swcursordraw(Point);
|
||||
void swcursorload(Cursor *);
|
||||
void swcursorinit(void);
|
|
@ -314,18 +314,36 @@ interrupt(Ureg*, void *arg)
|
|||
uartkick(uart);
|
||||
}
|
||||
|
||||
static void
|
||||
clkenable(Uart *u, int on)
|
||||
{
|
||||
char clk[32];
|
||||
|
||||
snprint(clk, sizeof(clk), "%s.ipg_perclk", u->name);
|
||||
if(on) setclkrate(clk, "osc_25m_ref_clk", u->freq);
|
||||
setclkgate(clk, on);
|
||||
}
|
||||
|
||||
static void
|
||||
disable(Uart *u)
|
||||
{
|
||||
u32int *regs = u->regs;
|
||||
|
||||
if(u->console)
|
||||
return; /* avoid glitch */
|
||||
|
||||
regs[UCR1] = 0;
|
||||
clkenable(u, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
enable(Uart *u, int ie)
|
||||
{
|
||||
disable(u);
|
||||
clkenable(u, 1);
|
||||
|
||||
if(ie) intrenable(IRQuart1, interrupt, u, BUSUNKNOWN, u->name);
|
||||
|
||||
config(u);
|
||||
}
|
||||
|
||||
|
|
|
@ -1774,9 +1774,64 @@ portreset(Hci *hp, int port, int on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clkenable(int i, int on)
|
||||
{
|
||||
char clk[32];
|
||||
|
||||
snprint(clk, sizeof(clk), "usb%d.ctrl", i+1);
|
||||
setclkgate(clk, on);
|
||||
snprint(clk, sizeof(clk), "usb%d.phy", i+1);
|
||||
setclkgate(clk, on);
|
||||
}
|
||||
|
||||
static void
|
||||
phyinit(u32int *reg)
|
||||
{
|
||||
enum {
|
||||
PHY_CTRL0 = 0x0/4,
|
||||
CTRL0_REF_SSP_EN = 1<<2,
|
||||
PHY_CTRL1 = 0x4/4,
|
||||
CTRL1_RESET = 1<<0,
|
||||
CTRL1_ATERESET = 1<<3,
|
||||
CTRL1_VDATSRCENB0 = 1<<19,
|
||||
CTRL1_VDATDETEBB0 = 1<<20,
|
||||
PHY_CTRL2 = 0x8/4,
|
||||
CTRL2_TXENABLEN0 = 1<<8,
|
||||
};
|
||||
reg[PHY_CTRL1] = (reg[PHY_CTRL1] & ~(CTRL1_VDATSRCENB0 | CTRL1_VDATDETEBB0)) | CTRL1_RESET | CTRL1_ATERESET;
|
||||
reg[PHY_CTRL0] |= CTRL0_REF_SSP_EN;
|
||||
reg[PHY_CTRL2] |= CTRL2_TXENABLEN0;
|
||||
reg[PHY_CTRL1] &= ~(CTRL1_RESET | CTRL1_ATERESET);
|
||||
}
|
||||
|
||||
static void
|
||||
coreinit(u32int *reg)
|
||||
{
|
||||
enum {
|
||||
GCTL = 0xC110/4,
|
||||
PWRDNSCALE_SHIFT = 19,
|
||||
PWRDNSCALE_MASK = 0x3FFF << PWRDNSCALE_SHIFT,
|
||||
PRTCAPDIR_SHIFT = 12,
|
||||
PRTCAPDIR_MASK = 3 << PRTCAPDIR_SHIFT,
|
||||
DISSCRAMBLE = 1<<3,
|
||||
DSBLCLKGTNG = 1<<0,
|
||||
|
||||
GFLADJ = 0xC630/4,
|
||||
GFLADJ_30MHZ_SDBND_SEL = 1<<7,
|
||||
GFLADJ_30MHZ_SHIFT = 0,
|
||||
GFLADJ_30MHZ_MASK = 0x3F << GFLADJ_30MHZ_SHIFT,
|
||||
|
||||
};
|
||||
reg[GCTL] &= ~(PWRDNSCALE_MASK | DISSCRAMBLE | DSBLCLKGTNG | PRTCAPDIR_MASK);
|
||||
reg[GCTL] |= 2<<PWRDNSCALE_SHIFT | 1<<PRTCAPDIR_SHIFT;
|
||||
reg[GFLADJ] = (reg[GFLADJ] & ~GFLADJ_30MHZ_MASK) | 0x20<<GFLADJ_30MHZ_SHIFT | GFLADJ_30MHZ_SDBND_SEL;
|
||||
}
|
||||
|
||||
static int
|
||||
reset(Hci *hp)
|
||||
{
|
||||
static char *powerdom[] = { "usb_otg1", "usb_otg2" };
|
||||
static Ctlr ctlrs[2];
|
||||
Ctlr *ctlr;
|
||||
int i;
|
||||
|
@ -1796,6 +1851,26 @@ reset(Hci *hp)
|
|||
return -1;
|
||||
|
||||
Found:
|
||||
if(i == 0){
|
||||
iomuxpad("pad_gpio1_io13", "usb1_otg_oc", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
|
||||
iomuxpad("pad_gpio1_io14", "gpio1_io14", "~LVTTL HYS PUE ~ODE FAST 45_OHM");
|
||||
|
||||
/* gpio1_io14: hub reset */
|
||||
gpioout(GPIO_PIN(1, 14), 0);
|
||||
microdelay(500);
|
||||
gpioout(GPIO_PIN(1, 14), 1);
|
||||
|
||||
for(i = 0; i < nelem(ctlrs); i++) clkenable(i, 0);
|
||||
setclkrate("ccm_usb_bus_clk_root", "system_pll2_div2", 500*Mhz);
|
||||
setclkrate("ccm_usb_core_ref_clk_root", "system_pll1_div8", 100*Mhz);
|
||||
setclkrate("ccm_usb_phy_ref_clk_root", "system_pll1_div8", 100*Mhz);
|
||||
i = 0;
|
||||
}
|
||||
powerup(powerdom[i]);
|
||||
clkenable(i, 1);
|
||||
phyinit(&ctlr->mmio[0xF0040/4]);
|
||||
coreinit(ctlr->mmio);
|
||||
|
||||
hp->init = init;
|
||||
hp->dump = dump;
|
||||
hp->interrupt = interrupt;
|
||||
|
|
532
sys/src/9/imx8/usdhc.c
Normal file
532
sys/src/9/imx8/usdhc.c
Normal file
|
@ -0,0 +1,532 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "../port/error.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/sd.h"
|
||||
|
||||
enum {
|
||||
Initfreq = 400000, /* initialisation frequency for MMC */
|
||||
SDfreq = 25*Mhz, /* standard SD frequency */
|
||||
SDfreqhs = 50*Mhz, /* highspeed frequency */
|
||||
DTO = 14, /* data timeout exponent (guesswork) */
|
||||
|
||||
GoIdle = 0, /* mmc/sdio go idle state */
|
||||
MMCSelect = 7, /* mmc/sd card select command */
|
||||
Setbuswidth = 6, /* mmc/sd set bus width command */
|
||||
Switchfunc = 6, /* mmc/sd switch function command */
|
||||
Voltageswitch = 11, /* md/sdio switch to 1.8V */
|
||||
IORWdirect = 52, /* sdio read/write direct command */
|
||||
IORWextended = 53, /* sdio read/write extended command */
|
||||
Appcmd = 55, /* mmc/sd application command prefix */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* Controller registers */
|
||||
SDMAaddr = 0x00>>2,
|
||||
Blksizecnt = 0x04>>2,
|
||||
Arg1 = 0x08>>2,
|
||||
Cmdtm = 0x0c>>2,
|
||||
Resp0 = 0x10>>2,
|
||||
Resp1 = 0x14>>2,
|
||||
Resp2 = 0x18>>2,
|
||||
Resp3 = 0x1c>>2,
|
||||
Data = 0x20>>2,
|
||||
Status = 0x24>>2,
|
||||
|
||||
Control0 = 0x28>>2,
|
||||
Control1 = 0x2c>>2,
|
||||
|
||||
Interrupt = 0x30>>2,
|
||||
Irptmask = 0x34>>2,
|
||||
Irpten = 0x38>>2,
|
||||
|
||||
Control2 = 0x3c>>2,
|
||||
Capability = 0x40>>2,
|
||||
|
||||
Mixctrl = 0x48>>2,
|
||||
|
||||
Forceirpt = 0x50>>2,
|
||||
Dmadesc = 0x58>>2,
|
||||
|
||||
Vendorspec = 0xC0>>2,
|
||||
|
||||
/* Vendorspec */
|
||||
ClkEn = 1<<14,
|
||||
PerEn = 1<<13,
|
||||
HclkEn = 1<<12,
|
||||
IpgEn = 1<<11,
|
||||
Vsel = 1<<1,
|
||||
|
||||
/* Control0 (PROT_CTRL) */
|
||||
Dmaselect = 3<<8,
|
||||
DmaSDMA = 0<<8,
|
||||
DmaADMA1 = 1<<8,
|
||||
DmaADMA2 = 2<<8,
|
||||
EMODE = 3<<4,
|
||||
BE = 0<<4,
|
||||
HBE = 1<<4,
|
||||
LE = 2<<4,
|
||||
DwidthMask = 3<<1,
|
||||
Dwidth8 = 2<<1,
|
||||
Dwidth4 = 1<<1,
|
||||
Dwidth1 = 0<<1,
|
||||
LED = 1<<0,
|
||||
|
||||
/* Control1 (SYS_CTRL) */
|
||||
Srstdata = 1<<26, /* reset data circuit */
|
||||
Srstcmd = 1<<25, /* reset command circuit */
|
||||
Srsthc = 1<<24, /* reset complete host controller */
|
||||
Datatoshift = 16, /* data timeout unit exponent */
|
||||
Datatomask = 0xF0000,
|
||||
SDCLKFSshift = 8,
|
||||
DVSshift = 4,
|
||||
|
||||
/* Cmdtm */
|
||||
Indexshift = 24,
|
||||
Suspend = 1<<22,
|
||||
Resume = 2<<22,
|
||||
Abort = 3<<22,
|
||||
Isdata = 1<<21,
|
||||
Ixchken = 1<<20,
|
||||
Crcchken = 1<<19,
|
||||
Respmask = 3<<16,
|
||||
Respnone = 0<<16,
|
||||
Resp136 = 1<<16,
|
||||
Resp48 = 2<<16,
|
||||
Resp48busy = 3<<16,
|
||||
|
||||
/* Mixctrl */
|
||||
Autocmd23 = 1<<7,
|
||||
Multiblock = 1<<5,
|
||||
Host2card = 0<<4,
|
||||
Card2host = 1<<4,
|
||||
DdrEn = 1<<3,
|
||||
Autocmd12 = 1<<2,
|
||||
Blkcnten = 1<<1,
|
||||
Dmaen = 1<<0,
|
||||
MixCmdMask = 0xFF ^ DdrEn,
|
||||
|
||||
/* Interrupt */
|
||||
Admaerr = 1<<28,
|
||||
Acmderr = 1<<24,
|
||||
Denderr = 1<<22,
|
||||
Dcrcerr = 1<<21,
|
||||
Dtoerr = 1<<20,
|
||||
Cbaderr = 1<<19,
|
||||
Cenderr = 1<<18,
|
||||
Ccrcerr = 1<<17,
|
||||
Ctoerr = 1<<16,
|
||||
Err = Admaerr|Acmderr|Denderr|Dcrcerr|Dtoerr|Cbaderr|Cenderr|Ccrcerr|Ctoerr,
|
||||
|
||||
Cardintr = 1<<8,
|
||||
Cardinsert = 1<<6,
|
||||
Readrdy = 1<<5,
|
||||
Writerdy = 1<<4,
|
||||
Dmaintr = 1<<3,
|
||||
Datadone = 1<<1,
|
||||
Cmddone = 1<<0,
|
||||
|
||||
/* Status */
|
||||
Bufread = 1<<11,
|
||||
Bufwrite = 1<<10,
|
||||
Readtrans = 1<<9,
|
||||
Writetrans = 1<<8,
|
||||
|
||||
Clkstable = 1<<3,
|
||||
|
||||
Datactive = 1<<2,
|
||||
Datinhibit = 1<<1,
|
||||
Cmdinhibit = 1<<0,
|
||||
};
|
||||
|
||||
static int cmdinfo[64] = {
|
||||
[0] Ixchken,
|
||||
[2] Resp136,
|
||||
[3] Resp48 | Ixchken | Crcchken,
|
||||
[5] Resp48,
|
||||
[6] Resp48 | Ixchken | Crcchken,
|
||||
[7] Resp48 | Ixchken | Crcchken,
|
||||
[8] Resp48 | Ixchken | Crcchken,
|
||||
[9] Resp136,
|
||||
[11] Resp48 | Ixchken | Crcchken,
|
||||
[13] Resp48 | Ixchken | Crcchken,
|
||||
[16] Resp48,
|
||||
[17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
|
||||
[18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken | Autocmd12,
|
||||
[24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
|
||||
[25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken | Autocmd12,
|
||||
[41] Resp48,
|
||||
[52] Resp48 | Ixchken | Crcchken,
|
||||
[53] Resp48 | Ixchken | Crcchken | Isdata,
|
||||
[55] Resp48 | Ixchken | Crcchken,
|
||||
};
|
||||
|
||||
typedef struct Adma Adma;
|
||||
typedef struct Ctlr Ctlr;
|
||||
|
||||
/*
|
||||
* ADMA2 descriptor
|
||||
* See SD Host Controller Simplified Specification Version 2.00
|
||||
*/
|
||||
struct Adma {
|
||||
u32int desc;
|
||||
u32int addr;
|
||||
};
|
||||
|
||||
enum {
|
||||
/* desc fields */
|
||||
Valid = 1<<0,
|
||||
End = 1<<1,
|
||||
Int = 1<<2,
|
||||
Nop = 0<<4,
|
||||
Tran = 2<<4,
|
||||
Link = 3<<4,
|
||||
OLength = 16,
|
||||
/* maximum value for Length field */
|
||||
Maxdma = 1<<12,
|
||||
};
|
||||
|
||||
struct Ctlr {
|
||||
Rendez r;
|
||||
int fastclock;
|
||||
uint extclk;
|
||||
int appcmd;
|
||||
Adma *dma;
|
||||
};
|
||||
|
||||
static Ctlr usdhc;
|
||||
|
||||
static void usdhcinterrupt(Ureg*, void*);
|
||||
|
||||
static u32int *regs = (u32int*)(VIRTIO+0xB50000); /* USDHC2 */
|
||||
#define RR(reg) (regs[reg])
|
||||
|
||||
static void
|
||||
WR(int reg, u32int val)
|
||||
{
|
||||
if(0)print("WR %2.2ux %ux\n", reg<<2, val);
|
||||
coherence();
|
||||
regs[reg] = val;
|
||||
}
|
||||
|
||||
static Adma*
|
||||
dmaalloc(void *addr, int len)
|
||||
{
|
||||
int n;
|
||||
uintptr a;
|
||||
Adma *adma, *p;
|
||||
|
||||
a = PADDR(addr);
|
||||
n = (len + Maxdma-1) / Maxdma;
|
||||
adma = sdmalloc(n * sizeof(Adma));
|
||||
for(p = adma; len > 0; p++){
|
||||
if(n == 1)
|
||||
p->desc = len<<OLength | End | Int | Valid | Tran;
|
||||
else
|
||||
p->desc = Maxdma<<OLength | Valid | Tran;
|
||||
p->addr = a;
|
||||
a += Maxdma;
|
||||
len -= Maxdma;
|
||||
n--;
|
||||
}
|
||||
cachedwbse(adma, (char*)p - (char*)adma);
|
||||
return adma;
|
||||
}
|
||||
|
||||
static void
|
||||
usdhcclk(uint freq)
|
||||
{
|
||||
uint pre_div = 1, post_div = 1, clk = usdhc.extclk;
|
||||
|
||||
while(clk / (pre_div * 16) > freq && pre_div < 256)
|
||||
pre_div <<= 1;
|
||||
|
||||
while(clk / (pre_div * post_div) > freq && post_div < 16)
|
||||
post_div++;
|
||||
|
||||
WR(Vendorspec, RR(Vendorspec) & ~ClkEn);
|
||||
WR(Control1, (pre_div>>1)<<SDCLKFSshift | (post_div-1)<<DVSshift | DTO<<Datatoshift);
|
||||
delay(10);
|
||||
WR(Vendorspec, RR(Vendorspec) | ClkEn | PerEn);
|
||||
while((RR(Status) & Clkstable) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int
|
||||
datadone(void*)
|
||||
{
|
||||
return RR(Interrupt) & (Datadone|Err);
|
||||
}
|
||||
|
||||
static int
|
||||
usdhcinit(void)
|
||||
{
|
||||
iomuxpad("pad_sd2_clk", "usdhc2_clk", "~LVTTL ~HYS ~PUE ~ODE SLOW 75_OHM");
|
||||
iomuxpad("pad_sd2_cmd", "usdhc2_cmd", "~LVTTL HYS PUE ~ODE SLOW 75_OHM");
|
||||
iomuxpad("pad_sd2_data0", "usdhc2_data0", "~LVTTL HYS PUE ~ODE SLOW 75_OHM");
|
||||
iomuxpad("pad_sd2_data1", "usdhc2_data1", "~LVTTL HYS PUE ~ODE SLOW 75_OHM");
|
||||
iomuxpad("pad_sd2_data2", "usdhc2_data2", "~LVTTL HYS PUE ~ODE SLOW 75_OHM");
|
||||
iomuxpad("pad_sd2_data3", "usdhc2_data3", "~LVTTL HYS PUE ~ODE SLOW 75_OHM");
|
||||
|
||||
setclkgate("usdhc2.ipg_clk", 0);
|
||||
setclkgate("usdhc2.ipg_clk_perclk", 0);
|
||||
setclkrate("usdhc2.ipg_clk_perclk", "system_pll1_clk", 200*Mhz);
|
||||
setclkgate("usdhc2.ipg_clk_perclk", 1);
|
||||
setclkgate("usdhc2.ipg_clk", 1);
|
||||
|
||||
usdhc.extclk = getclkrate("usdhc2.ipg_clk_perclk");
|
||||
if(usdhc.extclk <= 0){
|
||||
print("usdhc: usdhc2.ipg_clk_perclk not enabled\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(0)print("usdhc control %8.8ux %8.8ux %8.8ux\n",
|
||||
RR(Control0), RR(Control1), RR(Control2));
|
||||
|
||||
WR(Control1, Srsthc);
|
||||
delay(10);
|
||||
while(RR(Control1) & Srsthc)
|
||||
;
|
||||
WR(Control1, Srstdata);
|
||||
delay(10);
|
||||
WR(Control1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
usdhcinquiry(char *inquiry, int inqlen)
|
||||
{
|
||||
return snprint(inquiry, inqlen, "USDHC Host Controller");
|
||||
}
|
||||
|
||||
static void
|
||||
usdhcenable(void)
|
||||
{
|
||||
WR(Control0, 0);
|
||||
delay(1);
|
||||
WR(Vendorspec, RR(Vendorspec) & ~Vsel);
|
||||
WR(Control0, LE | Dwidth1 | DmaADMA2);
|
||||
WR(Control1, 0);
|
||||
delay(1);
|
||||
WR(Vendorspec, RR(Vendorspec) | HclkEn | IpgEn);
|
||||
usdhcclk(Initfreq);
|
||||
WR(Irpten, 0);
|
||||
WR(Irptmask, ~(Cardintr|Dmaintr));
|
||||
WR(Interrupt, ~0);
|
||||
intrenable(IRQusdhc2, usdhcinterrupt, nil, BUSUNKNOWN, "usdhc2");
|
||||
}
|
||||
|
||||
static int
|
||||
usdhccmd(u32int cmd, u32int arg, u32int *resp)
|
||||
{
|
||||
u32int c;
|
||||
int i;
|
||||
ulong now;
|
||||
|
||||
/* using Autocmd12 */
|
||||
if(cmd == 12)
|
||||
return 0;
|
||||
|
||||
assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
|
||||
c = (cmd << Indexshift) | cmdinfo[cmd];
|
||||
/*
|
||||
* CMD6 may be Setbuswidth or Switchfunc depending on Appcmd prefix
|
||||
*/
|
||||
if(cmd == Switchfunc && !usdhc.appcmd)
|
||||
c |= Isdata|Card2host;
|
||||
if(c & Isdata)
|
||||
c |= Dmaen;
|
||||
if(cmd == IORWextended){
|
||||
if(arg & (1<<31))
|
||||
c |= Host2card;
|
||||
else
|
||||
c |= Card2host;
|
||||
if((RR(Blksizecnt)&0xFFFF0000) != 0x10000)
|
||||
c |= Multiblock | Blkcnten;
|
||||
}
|
||||
/*
|
||||
* GoIdle indicates new card insertion: reset bus width & speed
|
||||
*/
|
||||
if(cmd == GoIdle){
|
||||
WR(Control0, (RR(Control0) & ~DwidthMask) | Dwidth1);
|
||||
usdhcclk(Initfreq);
|
||||
}
|
||||
if(RR(Status) & Cmdinhibit){
|
||||
print("usdhccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
|
||||
RR(Interrupt), RR(Status));
|
||||
WR(Control1, RR(Control1) | Srstcmd);
|
||||
while(RR(Control1) & Srstcmd)
|
||||
;
|
||||
while(RR(Status) & Cmdinhibit)
|
||||
;
|
||||
}
|
||||
if((RR(Status) & Datinhibit) &&
|
||||
((c & Isdata) || (c & Respmask) == Resp48busy)){
|
||||
print("usdhccmd: need to reset Datinhibit intr %ux stat %ux\n",
|
||||
RR(Interrupt), RR(Status));
|
||||
WR(Control1, RR(Control1) | Srstdata);
|
||||
while(RR(Control1) & Srstdata)
|
||||
;
|
||||
while(RR(Status) & Datinhibit)
|
||||
;
|
||||
}
|
||||
while(RR(Status) & Datactive)
|
||||
;
|
||||
WR(Arg1, arg);
|
||||
if((i = (RR(Interrupt) & ~Cardintr)) != 0){
|
||||
if(i != Cardinsert)
|
||||
print("usdhc: before command, intr was %ux\n", i);
|
||||
WR(Interrupt, i);
|
||||
}
|
||||
WR(Mixctrl, (RR(Mixctrl) & ~MixCmdMask) | (c & MixCmdMask));
|
||||
WR(Cmdtm, c & ~0xFFFF);
|
||||
|
||||
now = MACHP(0)->ticks;
|
||||
while(((i=RR(Interrupt))&(Cmddone|Err)) == 0)
|
||||
if(MACHP(0)->ticks - now > HZ)
|
||||
break;
|
||||
if((i&(Cmddone|Err)) != Cmddone){
|
||||
if((i&~(Err|Cardintr)) != Ctoerr)
|
||||
print("usdhc: cmd %ux arg %ux error intr %ux stat %ux\n", c, arg, i, RR(Status));
|
||||
WR(Interrupt, i);
|
||||
if(RR(Status)&Cmdinhibit){
|
||||
WR(Control1, RR(Control1)|Srstcmd);
|
||||
while(RR(Control1)&Srstcmd)
|
||||
;
|
||||
}
|
||||
error(Eio);
|
||||
}
|
||||
WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
|
||||
switch(c & Respmask){
|
||||
case Resp136:
|
||||
resp[0] = RR(Resp0)<<8;
|
||||
resp[1] = RR(Resp0)>>24 | RR(Resp1)<<8;
|
||||
resp[2] = RR(Resp1)>>24 | RR(Resp2)<<8;
|
||||
resp[3] = RR(Resp2)>>24 | RR(Resp3)<<8;
|
||||
break;
|
||||
case Resp48:
|
||||
case Resp48busy:
|
||||
resp[0] = RR(Resp0);
|
||||
break;
|
||||
case Respnone:
|
||||
resp[0] = 0;
|
||||
break;
|
||||
}
|
||||
if((c & Respmask) == Resp48busy){
|
||||
WR(Irpten, RR(Irpten)|Datadone|Err);
|
||||
tsleep(&usdhc.r, datadone, 0, 1000);
|
||||
i = RR(Interrupt);
|
||||
if((i & Datadone) == 0)
|
||||
print("usdhcio: no Datadone in %x after CMD%d\n", i, cmd);
|
||||
if(i & Err)
|
||||
print("usdhcio: CMD%d error interrupt %ux\n",
|
||||
cmd, RR(Interrupt));
|
||||
if(i != 0) WR(Interrupt, i);
|
||||
}
|
||||
/*
|
||||
* Once card is selected, use faster clock
|
||||
*/
|
||||
if(cmd == MMCSelect){
|
||||
usdhcclk(SDfreq);
|
||||
usdhc.fastclock = 1;
|
||||
}
|
||||
if(cmd == Setbuswidth){
|
||||
if(usdhc.appcmd){
|
||||
/*
|
||||
* If card bus width changes, change host bus width
|
||||
*/
|
||||
switch(arg){
|
||||
case 0:
|
||||
WR(Control0, (RR(Control0) & ~DwidthMask) | Dwidth1);
|
||||
break;
|
||||
case 2:
|
||||
WR(Control0, (RR(Control0) & ~DwidthMask) | Dwidth4);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If card switched into high speed mode, increase clock speed
|
||||
*/
|
||||
if((arg&0x8000000F) == 0x80000001){
|
||||
delay(1);
|
||||
usdhcclk(SDfreqhs);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
}else if(cmd == IORWdirect && (arg & ~0xFF) == (1<<31|0<<28|7<<9)){
|
||||
switch(arg & 0x3){
|
||||
case 0:
|
||||
WR(Control0, (RR(Control0) & ~DwidthMask) | Dwidth1);
|
||||
break;
|
||||
case 2:
|
||||
WR(Control0, (RR(Control0) & ~DwidthMask) | Dwidth4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
usdhc.appcmd = (cmd == Appcmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
usdhciosetup(int write, void *buf, int bsize, int bcount)
|
||||
{
|
||||
int len = bsize * bcount;
|
||||
assert(((uintptr)buf&3) == 0);
|
||||
assert((len&3) == 0);
|
||||
assert(bsize <= 2048);
|
||||
WR(Blksizecnt, bcount<<16 | bsize);
|
||||
if(usdhc.dma)
|
||||
sdfree(usdhc.dma);
|
||||
usdhc.dma = dmaalloc(buf, len);
|
||||
if(write)
|
||||
cachedwbse(buf, len);
|
||||
else
|
||||
cachedwbinvse(buf, len);
|
||||
WR(Dmadesc, PADDR(usdhc.dma));
|
||||
}
|
||||
|
||||
static void
|
||||
usdhcio(int write, uchar *buf, int len)
|
||||
{
|
||||
u32int i;
|
||||
|
||||
WR(Irpten, RR(Irpten) | Datadone|Err);
|
||||
tsleep(&usdhc.r, datadone, 0, 3000);
|
||||
WR(Irpten, RR(Irpten) & ~(Datadone|Err));
|
||||
i = RR(Interrupt);
|
||||
if((i & (Datadone|Err)) != Datadone){
|
||||
print("sdhc: %s error intr %ux stat %ux\n",
|
||||
write? "write" : "read", i, RR(Status));
|
||||
WR(Interrupt, i);
|
||||
error(Eio);
|
||||
}
|
||||
WR(Interrupt, i);
|
||||
if(!write)
|
||||
cachedinvse(buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
usdhcinterrupt(Ureg*, void*)
|
||||
{
|
||||
u32int i;
|
||||
|
||||
i = RR(Interrupt);
|
||||
if(i&(Datadone|Err))
|
||||
wakeup(&usdhc.r);
|
||||
WR(Irpten, RR(Irpten) & ~i);
|
||||
}
|
||||
|
||||
SDio sdio = {
|
||||
"usdhc",
|
||||
usdhcinit,
|
||||
usdhcenable,
|
||||
usdhcinquiry,
|
||||
usdhccmd,
|
||||
usdhciosetup,
|
||||
usdhcio,
|
||||
.highspeed = 1,
|
||||
.nomultiwrite = 1,
|
||||
};
|
|
@ -147,6 +147,7 @@ misc
|
|||
|
||||
dtracysys
|
||||
dtracytimer
|
||||
dtracydev
|
||||
|
||||
ip
|
||||
tcp
|
||||
|
|
|
@ -144,6 +144,7 @@ misc
|
|||
|
||||
dtracysys
|
||||
dtracytimer
|
||||
dtracydev
|
||||
|
||||
ip
|
||||
tcp
|
||||
|
|
|
@ -262,7 +262,7 @@ devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen
|
|||
if(strcmp(n, "..") == 0){
|
||||
if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
|
||||
print("devgen walk .. in dev%s %llux broken\n",
|
||||
devtab[nc->type]->name, nc->qid.path);
|
||||
devtab[c->type]->name, c->qid.path);
|
||||
error("broken devgen");
|
||||
}
|
||||
nc->qid = dir.qid;
|
||||
|
|
597
sys/src/9/port/devi2c.c
Normal file
597
sys/src/9/port/devi2c.c
Normal file
|
@ -0,0 +1,597 @@
|
|||
/* I²C bus driver */
|
||||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
#include "../port/i2c.h"
|
||||
|
||||
enum {
|
||||
Qdir = 0, /* #J */
|
||||
Qbus, /* #J/bus */
|
||||
Qctl, /* #J/bus/i2c.n.ctl */
|
||||
Qdata, /* #J/bus/i2c.n.data */
|
||||
};
|
||||
|
||||
#define TYPE(q) ((ulong)(q).path & 0x0F)
|
||||
#define BUS(q) (((ulong)(q).path>>4) & 0xFF)
|
||||
#define DEV(q) (((ulong)(q).path>>12) & 0xFFF)
|
||||
#define QID(d, b, t) (((d)<<12)|((b)<<4)|(t))
|
||||
|
||||
static I2Cbus *buses[16];
|
||||
|
||||
static I2Cdev *devs[1024];
|
||||
static Lock devslock;
|
||||
|
||||
static void probebus(I2Cbus *bus);
|
||||
|
||||
void
|
||||
addi2cbus(I2Cbus *bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(bus == nil)
|
||||
return;
|
||||
|
||||
for(i = 0; i < nelem(buses); i++){
|
||||
if(buses[i] == nil
|
||||
|| buses[i] == bus
|
||||
|| strcmp(bus->name, buses[i]->name) == 0){
|
||||
buses[i] = bus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I2Cbus*
|
||||
i2cbus(char *name)
|
||||
{
|
||||
I2Cbus *bus;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < nelem(buses); i++){
|
||||
bus = buses[i];
|
||||
if(bus == nil)
|
||||
break;
|
||||
if(strcmp(bus->name, name) == 0){
|
||||
probebus(bus);
|
||||
return bus;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
addi2cdev(I2Cdev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(dev == nil || dev->bus == nil)
|
||||
return;
|
||||
|
||||
lock(&devslock);
|
||||
for(i = 0; i < nelem(devs); i++){
|
||||
if(devs[i] == nil
|
||||
|| devs[i] == dev
|
||||
|| devs[i]->addr == dev->addr && devs[i]->bus == dev->bus){
|
||||
devs[i] = dev;
|
||||
unlock(&devslock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
unlock(&devslock);
|
||||
}
|
||||
|
||||
I2Cdev*
|
||||
i2cdev(I2Cbus *bus, int addr)
|
||||
{
|
||||
I2Cdev *dev;
|
||||
int i;
|
||||
|
||||
if(bus == nil || addr < 0 || addr >= 1<<10)
|
||||
return nil;
|
||||
|
||||
lock(&devslock);
|
||||
for(i = 0; i < nelem(devs) && (dev = devs[i]) != nil; i++){
|
||||
if(dev->addr == addr && dev->bus == bus){
|
||||
unlock(&devslock);
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
unlock(&devslock);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
enterbus(I2Cbus *bus)
|
||||
{
|
||||
if(up != nil && islo()){
|
||||
eqlock(bus);
|
||||
return 1;
|
||||
} else {
|
||||
while(!canqlock(bus))
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
leavebus(I2Cbus *bus)
|
||||
{
|
||||
qunlock(bus);
|
||||
}
|
||||
|
||||
int
|
||||
i2cbusio(I2Cbus *bus, uchar *pkt, int olen, int ilen)
|
||||
{
|
||||
int user, n;
|
||||
|
||||
user = enterbus(bus);
|
||||
if(!bus->probed){
|
||||
leavebus(bus);
|
||||
return -1;
|
||||
}
|
||||
if(user && waserror()){
|
||||
(*bus->io)(bus, nil, 0, 0);
|
||||
leavebus(bus);
|
||||
nexterror();
|
||||
}
|
||||
// iprint("%s: <- %.*H\n", bus->name, olen, pkt);
|
||||
n = (*bus->io)(bus, pkt, olen, ilen);
|
||||
// if(n > olen) iprint("%s: -> %.*H\n", bus->name, n - olen, pkt+olen);
|
||||
|
||||
leavebus(bus);
|
||||
if(user) poperror();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
putaddr(I2Cdev *dev, int isread, uchar *pkt, vlong addr)
|
||||
{
|
||||
int n, o = 0;
|
||||
|
||||
if(dev->a10){
|
||||
pkt[o++] = 0xF0 | (dev->addr>>(8-1))&6 | (isread != 0);
|
||||
pkt[o++] = dev->addr;
|
||||
} else
|
||||
pkt[o++] = dev->addr<<1 | (isread != 0);
|
||||
|
||||
if(addr >= 0){
|
||||
for(n=0; n<dev->subaddr; n++)
|
||||
pkt[o++] = addr >> (n*8);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
int
|
||||
i2csend(I2Cdev *dev, void *data, int len, vlong addr)
|
||||
{
|
||||
uchar pkt[138];
|
||||
int o;
|
||||
|
||||
o = putaddr(dev, 0, pkt, addr);
|
||||
if(o+len > sizeof(pkt))
|
||||
len = sizeof(pkt)-o;
|
||||
|
||||
if(len > 0)
|
||||
memmove(pkt+o, data, len);
|
||||
|
||||
return i2cbusio(dev->bus, pkt, o + len, 0) - o;
|
||||
}
|
||||
|
||||
int
|
||||
i2crecv(I2Cdev *dev, void *data, int len, vlong addr)
|
||||
{
|
||||
uchar pkt[138];
|
||||
int o;
|
||||
|
||||
o = putaddr(dev, 1, pkt, addr);
|
||||
if(o+len > sizeof(pkt))
|
||||
len = sizeof(pkt)-o;
|
||||
|
||||
len = i2cbusio(dev->bus, pkt, o, len) - o;
|
||||
if(len > 0)
|
||||
memmove(data, pkt+o, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
i2cquick(I2Cdev *dev, int rw)
|
||||
{
|
||||
uchar pkt[2];
|
||||
int o = putaddr(dev, rw, pkt, -1);
|
||||
if(i2cbusio(dev->bus, pkt, o, 0) != o)
|
||||
return -1;
|
||||
return rw != 0;
|
||||
}
|
||||
int
|
||||
i2crecvbyte(I2Cdev *dev)
|
||||
{
|
||||
uchar pkt[2+1];
|
||||
int o = putaddr(dev, 1, pkt, -1);
|
||||
if(i2cbusio(dev->bus, pkt, o, 1) - o != 1)
|
||||
return -1;
|
||||
return pkt[o];
|
||||
}
|
||||
int
|
||||
i2csendbyte(I2Cdev *dev, uchar b)
|
||||
{
|
||||
uchar pkt[2+1];
|
||||
int o = putaddr(dev, 0, pkt, -1);
|
||||
pkt[o] = b;
|
||||
if(i2cbusio(dev->bus, pkt, o+1, 0) - o != 1)
|
||||
return -1;
|
||||
return b;
|
||||
}
|
||||
int
|
||||
i2creadbyte(I2Cdev *dev, ulong addr)
|
||||
{
|
||||
uchar pkt[2+4+1];
|
||||
int o = putaddr(dev, 1, pkt, addr);
|
||||
if(i2cbusio(dev->bus, pkt, o, 1) - o != 1)
|
||||
return -1;
|
||||
return pkt[o];
|
||||
}
|
||||
int
|
||||
i2cwritebyte(I2Cdev *dev, ulong addr, uchar b)
|
||||
{
|
||||
uchar pkt[2+4+1];
|
||||
int o = putaddr(dev, 0, pkt, addr);
|
||||
pkt[o] = b;
|
||||
if(i2cbusio(dev->bus, pkt, o+1, 0) - o != 1)
|
||||
return -1;
|
||||
return b;
|
||||
}
|
||||
int
|
||||
i2creadword(I2Cdev *dev, ulong addr)
|
||||
{
|
||||
uchar pkt[2+4+2];
|
||||
int o = putaddr(dev, 1, pkt, addr);
|
||||
if(i2cbusio(dev->bus, pkt, o, 2) - o != 2)
|
||||
return -1;
|
||||
return pkt[o] | (ushort)pkt[o+1]<<8;
|
||||
}
|
||||
int
|
||||
i2cwriteword(I2Cdev *dev, ulong addr, ushort w)
|
||||
{
|
||||
uchar pkt[2+4+2];
|
||||
int o = putaddr(dev, 0, pkt, addr);
|
||||
pkt[o+0] = w;
|
||||
pkt[o+1] = w>>8;
|
||||
if(i2cbusio(dev->bus, pkt, o+2, 0) - o != 2)
|
||||
return -1;
|
||||
return w;
|
||||
}
|
||||
vlong
|
||||
i2cread32(I2Cdev *dev, ulong addr)
|
||||
{
|
||||
uchar pkt[2+4+4];
|
||||
int o = putaddr(dev, 1, pkt, addr);
|
||||
if(i2cbusio(dev->bus, pkt, o, 4) - o != 4)
|
||||
return -1;
|
||||
return pkt[o] | (ulong)pkt[o+1]<<8 | (ulong)pkt[o+2]<<16 | (ulong)pkt[o+3]<<24;
|
||||
}
|
||||
vlong
|
||||
i2cwrite32(I2Cdev *dev, ulong addr, ulong u)
|
||||
{
|
||||
uchar pkt[2+4+4];
|
||||
int o = putaddr(dev, 0, pkt, addr);
|
||||
pkt[o+0] = u;
|
||||
pkt[o+1] = u>>8;
|
||||
pkt[o+2] = u>>16;
|
||||
pkt[o+3] = u>>24;
|
||||
if(i2cbusio(dev->bus, pkt, o+4, 0) - o != 4)
|
||||
return -1;
|
||||
return u;
|
||||
}
|
||||
|
||||
static void
|
||||
probeddev(I2Cdev *dummy)
|
||||
{
|
||||
I2Cdev *dev = smalloc(sizeof(I2Cdev));
|
||||
memmove(dev, dummy, sizeof(I2Cdev));
|
||||
addi2cdev(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
probebus(I2Cbus *bus)
|
||||
{
|
||||
I2Cdev dummy;
|
||||
uchar pkt[2];
|
||||
int user, n;
|
||||
|
||||
if(bus->probed)
|
||||
return;
|
||||
|
||||
user = enterbus(bus);
|
||||
if(bus->probed){
|
||||
leavebus(bus);
|
||||
return;
|
||||
}
|
||||
if(user && waserror()
|
||||
|| (*bus->init)(bus)){
|
||||
leavebus(bus);
|
||||
if(user) nexterror();
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
dummy.bus = bus;
|
||||
|
||||
dummy.a10 = 0;
|
||||
for(dummy.addr = 8; dummy.addr < 0x78; dummy.addr++) {
|
||||
if(i2cdev(bus, dummy.addr) != nil)
|
||||
continue;
|
||||
if(user && waserror()){
|
||||
(*bus->io)(bus, nil, 0, 0);
|
||||
continue;
|
||||
}
|
||||
n = putaddr(&dummy, 0, pkt, -1);
|
||||
if((*bus->io)(bus, pkt, n, 0) == n)
|
||||
probeddev(&dummy);
|
||||
if(user) poperror();
|
||||
}
|
||||
|
||||
dummy.a10 = 1;
|
||||
for(dummy.addr = 0; dummy.addr < (1<<10); dummy.addr++) {
|
||||
if(i2cdev(bus, dummy.addr) != nil)
|
||||
continue;
|
||||
if(user && waserror()){
|
||||
(*bus->io)(bus, nil, 0, 0);
|
||||
continue;
|
||||
}
|
||||
n = putaddr(&dummy, 0, pkt, -1);
|
||||
if((*bus->io)(bus, pkt, n, 0) == n)
|
||||
probeddev(&dummy);
|
||||
if(user) poperror();
|
||||
}
|
||||
|
||||
bus->probed = 1;
|
||||
leavebus(bus);
|
||||
if(user) poperror();
|
||||
}
|
||||
|
||||
static int
|
||||
i2cgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
|
||||
{
|
||||
I2Cbus *bus;
|
||||
I2Cdev *dev;
|
||||
|
||||
Qid q;
|
||||
|
||||
switch(TYPE(c->qid)){
|
||||
case Qdir:
|
||||
if(s == DEVDOTDOT){
|
||||
Gendir:
|
||||
mkqid(&q, QID(0, 0, Qdir), 0, QTDIR);
|
||||
snprint(up->genbuf, sizeof up->genbuf, "#J");
|
||||
devdir(c, q, up->genbuf, 0, eve, 0500, dp);
|
||||
return 1;
|
||||
}
|
||||
if(s >= nelem(buses))
|
||||
return -1;
|
||||
bus = buses[s];
|
||||
if(bus == nil)
|
||||
return -1;
|
||||
mkqid(&q, QID(0, s, Qbus), 0, QTDIR);
|
||||
devdir(c, q, bus->name, 0, eve, 0500, dp);
|
||||
return 1;
|
||||
case Qbus:
|
||||
if(s == DEVDOTDOT)
|
||||
goto Gendir;
|
||||
if((s/2) >= nelem(devs))
|
||||
return -1;
|
||||
|
||||
bus = buses[BUS(c->qid)];
|
||||
probebus(bus);
|
||||
|
||||
lock(&devslock);
|
||||
dev = devs[s/2];
|
||||
unlock(&devslock);
|
||||
|
||||
if(dev == nil)
|
||||
return -1;
|
||||
if(dev->bus != bus)
|
||||
return 0;
|
||||
if(s & 1){
|
||||
mkqid(&q, QID(dev->addr, BUS(c->qid), Qdata), 0, 0);
|
||||
goto Gendata;
|
||||
}
|
||||
mkqid(&q, QID(dev->addr, BUS(c->qid), Qctl), 0, 0);
|
||||
goto Genctl;
|
||||
case Qctl:
|
||||
q = c->qid;
|
||||
Genctl:
|
||||
snprint(up->genbuf, sizeof up->genbuf, "i2c.%lux.ctl", DEV(q));
|
||||
devdir(c, q, up->genbuf, 0, eve, 0600, dp);
|
||||
return 1;
|
||||
case Qdata:
|
||||
q = c->qid;
|
||||
bus = buses[BUS(q)];
|
||||
dev = i2cdev(bus, DEV(q));
|
||||
if(dev == nil)
|
||||
return -1;
|
||||
Gendata:
|
||||
snprint(up->genbuf, sizeof up->genbuf, "i2c.%lux.data", DEV(q));
|
||||
devdir(c, q, up->genbuf, dev->size, eve, 0600, dp);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
i2cattach(char *spec)
|
||||
{
|
||||
return devattach('J', spec);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
i2copen(Chan *c, int mode)
|
||||
{
|
||||
c = devopen(c, mode, nil, 0, i2cgen);
|
||||
switch(TYPE(c->qid)){
|
||||
case Qctl:
|
||||
case Qdata:
|
||||
c->aux = i2cdev(buses[BUS(c->qid)], DEV(c->qid));
|
||||
if(c->aux == nil)
|
||||
error(Enonexist);
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
enum {
|
||||
CMsize,
|
||||
CMsubaddress,
|
||||
};
|
||||
|
||||
static Cmdtab i2cctlmsg[] =
|
||||
{
|
||||
CMsize, "size", 2,
|
||||
CMsubaddress, "subaddress", 2,
|
||||
};
|
||||
|
||||
static long
|
||||
i2cwrctl(I2Cdev *dev, void *data, long len)
|
||||
{
|
||||
Cmdbuf *cb;
|
||||
Cmdtab *ct;
|
||||
ulong u;
|
||||
|
||||
cb = parsecmd(data, len);
|
||||
if(waserror()){
|
||||
free(cb);
|
||||
nexterror();
|
||||
}
|
||||
ct = lookupcmd(cb, i2cctlmsg, nelem(i2cctlmsg));
|
||||
switch(ct->index){
|
||||
case CMsize:
|
||||
dev->size = strtoul(cb->f[1], nil, 0);
|
||||
break;
|
||||
case CMsubaddress:
|
||||
u = strtoul(cb->f[1], nil, 0);
|
||||
if(u > 4)
|
||||
cmderror(cb, Ebadarg);
|
||||
dev->subaddr = u;
|
||||
break;
|
||||
default:
|
||||
cmderror(cb, Ebadarg);
|
||||
}
|
||||
free(cb);
|
||||
poperror();
|
||||
return len;
|
||||
}
|
||||
|
||||
static long
|
||||
i2crdctl(I2Cdev *dev, void *data, long len, vlong offset)
|
||||
{
|
||||
char cfg[64];
|
||||
|
||||
snprint(cfg, sizeof(cfg), "size %lud\nsubaddress %d\n", dev->size, dev->subaddr);
|
||||
return readstr((ulong)offset, data, len, cfg);
|
||||
}
|
||||
|
||||
static long
|
||||
i2cwrite(Chan *c, void *data, long len, vlong offset)
|
||||
{
|
||||
I2Cdev *dev;
|
||||
|
||||
switch(TYPE(c->qid)){
|
||||
default:
|
||||
error(Egreg);
|
||||
return -1;
|
||||
case Qctl:
|
||||
dev = c->aux;
|
||||
return i2cwrctl(dev, data, len);
|
||||
case Qdata:
|
||||
break;
|
||||
}
|
||||
dev = c->aux;
|
||||
if(dev->size){
|
||||
if(offset+len > dev->size){
|
||||
if(offset >= dev->size)
|
||||
return 0;
|
||||
len = dev->size - offset;
|
||||
}
|
||||
}
|
||||
len = i2csend(dev, data, len, offset);
|
||||
if(len < 0)
|
||||
error(Eio);
|
||||
return len;
|
||||
}
|
||||
|
||||
static long
|
||||
i2cread(Chan *c, void *data, long len, vlong offset)
|
||||
{
|
||||
I2Cdev *dev;
|
||||
|
||||
if(c->qid.type == QTDIR)
|
||||
return devdirread(c, data, len, nil, 0, i2cgen);
|
||||
|
||||
switch(TYPE(c->qid)){
|
||||
default:
|
||||
error(Egreg);
|
||||
case Qctl:
|
||||
dev = c->aux;
|
||||
return i2crdctl(dev, data, len, offset);
|
||||
case Qdata:
|
||||
break;
|
||||
}
|
||||
dev = c->aux;
|
||||
if(dev->size){
|
||||
if(offset+len > dev->size){
|
||||
if(offset >= dev->size)
|
||||
return 0;
|
||||
len = dev->size - offset;
|
||||
}
|
||||
}
|
||||
len = i2crecv(dev, data, len, offset);
|
||||
if(len < 0)
|
||||
error(Eio);
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
i2cclose(Chan*)
|
||||
{
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
i2cwalk(Chan *c, Chan *nc, char **name, int nname)
|
||||
{
|
||||
return devwalk(c, nc, name, nname, nil, 0, i2cgen);
|
||||
}
|
||||
|
||||
static int
|
||||
i2cstat(Chan *c, uchar *dp, int n)
|
||||
{
|
||||
return devstat(c, dp, n, nil, 0, i2cgen);
|
||||
}
|
||||
|
||||
Dev i2cdevtab = {
|
||||
'J',
|
||||
"i2c",
|
||||
|
||||
devreset,
|
||||
devinit,
|
||||
devshutdown,
|
||||
i2cattach,
|
||||
i2cwalk,
|
||||
i2cstat,
|
||||
i2copen,
|
||||
devcreate,
|
||||
i2cclose,
|
||||
i2cread,
|
||||
devbread,
|
||||
i2cwrite,
|
||||
devbwrite,
|
||||
devremove,
|
||||
devwstat,
|
||||
devpower,
|
||||
};
|
|
@ -11,9 +11,7 @@ typedef struct Pipe Pipe;
|
|||
struct Pipe
|
||||
{
|
||||
QLock;
|
||||
Pipe *next;
|
||||
int ref;
|
||||
ulong path;
|
||||
Queue *q[2];
|
||||
int qref[2];
|
||||
};
|
||||
|
@ -57,6 +55,7 @@ pipeattach(char *spec)
|
|||
{
|
||||
Pipe *p;
|
||||
Chan *c;
|
||||
ulong path;
|
||||
|
||||
c = devattach('|', spec);
|
||||
if(waserror()){
|
||||
|
@ -82,10 +81,10 @@ pipeattach(char *spec)
|
|||
poperror();
|
||||
|
||||
lock(&pipealloc);
|
||||
p->path = ++pipealloc.path;
|
||||
path = ++pipealloc.path;
|
||||
unlock(&pipealloc);
|
||||
|
||||
mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
|
||||
mkqid(&c->qid, NETQID(path, Qdir), 0, QTDIR);
|
||||
c->aux = p;
|
||||
c->dev = 0;
|
||||
return c;
|
||||
|
|
|
@ -5,80 +5,249 @@
|
|||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
#include "netif.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
struct Link
|
||||
{
|
||||
void *link;
|
||||
char *name;
|
||||
ulong path;
|
||||
};
|
||||
|
||||
typedef struct Srv Srv;
|
||||
struct Srv
|
||||
{
|
||||
char *name;
|
||||
Link;
|
||||
|
||||
char *owner;
|
||||
ulong perm;
|
||||
Chan *chan;
|
||||
Srv *link;
|
||||
ulong path;
|
||||
};
|
||||
|
||||
static QLock srvlk;
|
||||
static Srv *srv;
|
||||
static int qidpath;
|
||||
|
||||
static Srv*
|
||||
srvlookup(char *name, ulong qidpath)
|
||||
typedef struct Board Board;
|
||||
struct Board
|
||||
{
|
||||
Srv *sp;
|
||||
Link;
|
||||
RWlock;
|
||||
Ref;
|
||||
|
||||
for(sp = srv; sp != nil; sp = sp->link) {
|
||||
if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
|
||||
return sp;
|
||||
Board *parent;
|
||||
Board *child;
|
||||
Srv *srv;
|
||||
long id;
|
||||
int qidpath;
|
||||
int closed;
|
||||
};
|
||||
|
||||
struct{
|
||||
QLock;
|
||||
long path;
|
||||
} boards;
|
||||
|
||||
enum{
|
||||
Qroot,
|
||||
Qclone,
|
||||
Qlease,
|
||||
|
||||
Qend,
|
||||
};
|
||||
|
||||
Board root;
|
||||
|
||||
static char Eexpired[] = "expired lease";
|
||||
|
||||
static void*
|
||||
lookup(Link *l, char *name, ulong qidpath)
|
||||
{
|
||||
Link *lp;
|
||||
|
||||
if(qidpath != ~0UL)
|
||||
qidpath = NETTYPE(qidpath);
|
||||
for(lp = l; lp != nil; lp = lp->link){
|
||||
if(qidpath != ~0UL && lp->path == qidpath)
|
||||
return lp;
|
||||
if(name != nil && strcmp(lp->name, name) == 0)
|
||||
return lp;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void*
|
||||
remove(Link **l, char *name, ulong qidpath)
|
||||
{
|
||||
Link *lp;
|
||||
Link **last;
|
||||
|
||||
if(qidpath != ~0UL)
|
||||
qidpath = NETTYPE(qidpath);
|
||||
last = l;
|
||||
for(lp = *l; lp != nil; lp = lp->link){
|
||||
if(qidpath != ~0UL && lp->path == qidpath)
|
||||
break;
|
||||
if(name != nil && strcmp(lp->name, name) == 0)
|
||||
break;
|
||||
last = &lp->link;
|
||||
}
|
||||
if(lp == nil)
|
||||
return nil;
|
||||
|
||||
*last = lp->link;
|
||||
lp->link = nil;
|
||||
return lp;
|
||||
}
|
||||
|
||||
static void
|
||||
boardclunk(Board *b, int close)
|
||||
{
|
||||
Srv *sp, *prv;
|
||||
Board *ch;
|
||||
long ref;
|
||||
|
||||
/* caller holds a wlock */
|
||||
if(b == &root){
|
||||
wunlock(b);
|
||||
return;
|
||||
}
|
||||
|
||||
if(close){
|
||||
assert(b->closed == 0);
|
||||
b->closed++;
|
||||
for(sp = b->srv; sp != nil; sp = prv){
|
||||
prv = sp->link;
|
||||
free(sp->owner);
|
||||
free(sp->name);
|
||||
if(sp->chan != nil)
|
||||
cclose(sp->chan);
|
||||
free(sp);
|
||||
}
|
||||
b->srv = nil;
|
||||
}
|
||||
ref = decref(b);
|
||||
|
||||
/*
|
||||
* All boards must be walkable from root. So a board
|
||||
* is allowed to sit at zero references as long as it
|
||||
* still has active children. For leaf nodes we then
|
||||
* have to walk up the tree to clear now empty parents.
|
||||
*/
|
||||
while(b->closed && b->child == nil && ref == 0){
|
||||
//Root should never be closed
|
||||
assert(b->parent != nil);
|
||||
wlock(b->parent);
|
||||
ch = remove((Link**)&b->parent->child, b->name, b->path);
|
||||
assert(ch == b);
|
||||
|
||||
b = ch->parent;
|
||||
free(ch->name);
|
||||
wunlock(ch);
|
||||
free(ch);
|
||||
}
|
||||
wunlock(b);
|
||||
}
|
||||
|
||||
static int
|
||||
srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
|
||||
{
|
||||
Srv *sp;
|
||||
Board *b, *ch;
|
||||
Qid q;
|
||||
|
||||
if(s == DEVDOTDOT){
|
||||
devdir(c, c->qid, "#s", 0, eve, 0555, dp);
|
||||
return 1;
|
||||
}
|
||||
if(name != nil && strlen(name) >= sizeof(up->genbuf))
|
||||
return -1;
|
||||
|
||||
qlock(&srvlk);
|
||||
if(name != nil)
|
||||
sp = srvlookup(name, -1);
|
||||
else {
|
||||
for(sp = srv; sp != nil && s > 0; sp = sp->link)
|
||||
s--;
|
||||
}
|
||||
if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) {
|
||||
qunlock(&srvlk);
|
||||
b = c->aux;
|
||||
ch = nil;
|
||||
mkqid(&q, ~0L, 0, QTFILE);
|
||||
rlock(b);
|
||||
if(waserror()){
|
||||
runlock(b);
|
||||
return -1;
|
||||
}
|
||||
mkqid(&q, sp->path, 0, QTFILE);
|
||||
/* make sure name string continues to exist after we release lock */
|
||||
kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
|
||||
devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
|
||||
qunlock(&srvlk);
|
||||
if(s == DEVDOTDOT){
|
||||
ch = b->parent;
|
||||
if(ch == nil)
|
||||
ch = &root;
|
||||
goto Child;
|
||||
|
||||
}
|
||||
if(name != nil){
|
||||
if(strcmp("clone", name) == 0)
|
||||
goto Clone;
|
||||
|
||||
sp = lookup(b->srv, name, ~0UL);
|
||||
if(sp == nil)
|
||||
ch = lookup(b->child, name, ~0UL);
|
||||
} else {
|
||||
if(s == 0)
|
||||
goto Clone;
|
||||
s--;
|
||||
for(sp = b->srv; sp != nil && s > 0; sp = sp->link)
|
||||
s--;
|
||||
for(ch = b->child; ch != nil && s > 0; ch = ch->link)
|
||||
s--;
|
||||
}
|
||||
if(sp != nil){
|
||||
kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
|
||||
q.vers = NETID(c->qid.path);
|
||||
q.path = NETQID(q.vers, sp->path);
|
||||
devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
|
||||
} else if(ch != nil){
|
||||
Child:
|
||||
kstrcpy(up->genbuf, ch->name, sizeof up->genbuf);
|
||||
q.vers = ch->id;
|
||||
q.path = NETQID(q.vers, ch->path);
|
||||
q.type = QTDIR;
|
||||
devdir(c, q, up->genbuf, 0, eve, 0555|DMDIR, dp);
|
||||
/* dirread's and stats shouldn't alter c->aux */
|
||||
if(name != nil)
|
||||
c->aux = ch;
|
||||
} else if(0){
|
||||
Clone:
|
||||
q.vers = NETID(c->qid.path);
|
||||
q.path = NETQID(q.vers, Qclone);
|
||||
devdir(c, q, "clone", 0, eve, 0444, dp);
|
||||
} else
|
||||
error(Enonexist);
|
||||
|
||||
runlock(b);
|
||||
poperror();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
srvinit(void)
|
||||
{
|
||||
qidpath = 1;
|
||||
root.qidpath = Qend;
|
||||
root.name = "#s";
|
||||
}
|
||||
|
||||
static Chan*
|
||||
srvattach(char *spec)
|
||||
{
|
||||
return devattach('s', spec);
|
||||
Chan *c;
|
||||
|
||||
c = devattach('s', spec);
|
||||
c->aux = &root;
|
||||
return c;
|
||||
}
|
||||
|
||||
static Walkqid*
|
||||
srvwalk(Chan *c, Chan *nc, char **name, int nname)
|
||||
{
|
||||
return devwalk(c, nc, name, nname, 0, 0, srvgen);
|
||||
Board *b;
|
||||
Walkqid *wq;
|
||||
|
||||
wq = devwalk(c, nc, name, nname, 0, 0, srvgen);
|
||||
if(wq == nil || wq->clone == nil)
|
||||
return wq;
|
||||
|
||||
b = wq->clone->aux;
|
||||
if(b == &root)
|
||||
return wq;
|
||||
|
||||
incref(b);
|
||||
return wq;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -90,12 +259,14 @@ srvstat(Chan *c, uchar *db, int n)
|
|||
char*
|
||||
srvname(Chan *c)
|
||||
{
|
||||
Board *b;
|
||||
Srv *sp;
|
||||
char *s;
|
||||
|
||||
s = nil;
|
||||
qlock(&srvlk);
|
||||
for(sp = srv; sp != nil; sp = sp->link) {
|
||||
b = &root;
|
||||
rlock(b);
|
||||
for(sp = b->srv; sp != nil; sp = sp->link) {
|
||||
if(sp->chan == c){
|
||||
s = malloc(3+strlen(sp->name)+1);
|
||||
if(s != nil)
|
||||
|
@ -103,15 +274,17 @@ srvname(Chan *c)
|
|||
break;
|
||||
}
|
||||
}
|
||||
qunlock(&srvlk);
|
||||
runlock(b);
|
||||
return s;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
srvopen(Chan *c, int omode)
|
||||
{
|
||||
Board *b, *ch;
|
||||
Srv *sp;
|
||||
Chan *nc;
|
||||
char buf[64];
|
||||
|
||||
if(c->qid.type == QTDIR){
|
||||
if(omode & ORCLOSE)
|
||||
|
@ -123,20 +296,53 @@ srvopen(Chan *c, int omode)
|
|||
c->offset = 0;
|
||||
return c;
|
||||
}
|
||||
qlock(&srvlk);
|
||||
if(waserror()){
|
||||
qunlock(&srvlk);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
sp = srvlookup(nil, c->qid.path);
|
||||
if(sp == nil || sp->chan == nil)
|
||||
error(Eshutdown);
|
||||
|
||||
if(omode&OTRUNC)
|
||||
error(Eexist);
|
||||
if(omode&ORCLOSE)
|
||||
error(Eperm);
|
||||
|
||||
b = c->aux;
|
||||
if(NETTYPE(c->qid.path) == Qclone){;
|
||||
wlock(b);
|
||||
if(b->closed){
|
||||
wunlock(b);
|
||||
error(Eexpired);
|
||||
}
|
||||
ch = smalloc(sizeof *ch);
|
||||
ch->qidpath = Qend;
|
||||
ch->ref = 1;
|
||||
do {
|
||||
qlock(&boards);
|
||||
ch->id = ++boards.path;
|
||||
qunlock(&boards);
|
||||
snprint(buf, sizeof buf, "%ld", ch->id);
|
||||
} while(lookup(b->srv, buf, ~0UL) != nil);
|
||||
|
||||
ch->parent = b;
|
||||
ch->path = b->qidpath++;
|
||||
kstrdup(&ch->name, buf);
|
||||
|
||||
ch->link = b->child;
|
||||
b->child = ch;
|
||||
c->aux = ch;
|
||||
c->qid.vers = ch->id;
|
||||
c->qid.path = NETQID(ch->id, Qlease);
|
||||
boardclunk(b, 0); //unlock
|
||||
return c;
|
||||
}
|
||||
|
||||
rlock(b);
|
||||
if(waserror()){
|
||||
runlock(b);
|
||||
nexterror();
|
||||
}
|
||||
if(b->closed)
|
||||
error(Eexpired);
|
||||
|
||||
sp = lookup(b->srv, nil, c->qid.path);
|
||||
if(sp == nil || sp->chan == nil)
|
||||
error(Eshutdown);
|
||||
|
||||
if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
|
||||
error(Eperm);
|
||||
devpermcheck(sp->owner, sp->perm, omode);
|
||||
|
@ -144,7 +350,7 @@ srvopen(Chan *c, int omode)
|
|||
nc = sp->chan;
|
||||
incref(nc);
|
||||
|
||||
qunlock(&srvlk);
|
||||
runlock(b);
|
||||
poperror();
|
||||
|
||||
cclose(c);
|
||||
|
@ -154,6 +360,7 @@ srvopen(Chan *c, int omode)
|
|||
static Chan*
|
||||
srvcreate(Chan *c, char *name, int omode, ulong perm)
|
||||
{
|
||||
Board *b;
|
||||
Srv *sp;
|
||||
|
||||
if(openmode(omode) != OWRITE)
|
||||
|
@ -166,27 +373,33 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
|
|||
kstrdup(&sp->name, name);
|
||||
kstrdup(&sp->owner, up->user);
|
||||
|
||||
qlock(&srvlk);
|
||||
b = c->aux;
|
||||
wlock(b);
|
||||
if(waserror()){
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
free(sp->owner);
|
||||
free(sp->name);
|
||||
free(sp);
|
||||
nexterror();
|
||||
}
|
||||
if(srvlookup(name, -1) != nil)
|
||||
if(b->closed)
|
||||
error(Eexpired);
|
||||
if(lookup(b->srv, name, ~0UL) != nil)
|
||||
error(Eexist);
|
||||
if(lookup(b->child, name, ~0UL) != nil)
|
||||
error(Eexist);
|
||||
|
||||
sp->perm = perm&0777;
|
||||
sp->path = qidpath++;
|
||||
sp->path = b->qidpath++;
|
||||
|
||||
c->qid.path = sp->path;
|
||||
c->qid.path = NETQID(b->id, sp->path);
|
||||
c->qid.vers = b->id;
|
||||
c->qid.type = QTFILE;
|
||||
|
||||
sp->link = srv;
|
||||
srv = sp;
|
||||
sp->link = b->srv;
|
||||
b->srv = sp;
|
||||
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
poperror();
|
||||
|
||||
c->flag |= COPEN;
|
||||
|
@ -198,22 +411,24 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
|
|||
static void
|
||||
srvremove(Chan *c)
|
||||
{
|
||||
Srv *sp, **l;
|
||||
Board *b;
|
||||
Srv *sp;
|
||||
|
||||
if(c->qid.type == QTDIR)
|
||||
error(Eperm);
|
||||
switch(NETTYPE(c->qid.path)){
|
||||
case Qlease:
|
||||
case Qclone:
|
||||
error(Eperm);
|
||||
}
|
||||
|
||||
qlock(&srvlk);
|
||||
b = c->aux;
|
||||
wlock(b);
|
||||
if(waserror()){
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
nexterror();
|
||||
}
|
||||
l = &srv;
|
||||
for(sp = *l; sp != nil; sp = *l) {
|
||||
if(sp->path == c->qid.path)
|
||||
break;
|
||||
l = &sp->link;
|
||||
}
|
||||
sp = lookup(b->srv, nil, c->qid.path);
|
||||
if(sp == nil)
|
||||
error(Enonexist);
|
||||
|
||||
|
@ -229,10 +444,9 @@ srvremove(Chan *c)
|
|||
if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
|
||||
error(Eperm);
|
||||
|
||||
*l = sp->link;
|
||||
sp->link = nil;
|
||||
remove((Link**)&b->srv, nil, c->qid.path);
|
||||
|
||||
qunlock(&srvlk);
|
||||
boardclunk(b, 0); //unlock
|
||||
poperror();
|
||||
|
||||
if(sp->chan != nil)
|
||||
|
@ -245,12 +459,18 @@ srvremove(Chan *c)
|
|||
static int
|
||||
srvwstat(Chan *c, uchar *dp, int n)
|
||||
{
|
||||
Board *b;
|
||||
char *strs;
|
||||
Srv *sp;
|
||||
Dir d;
|
||||
|
||||
if(c->qid.type & QTDIR)
|
||||
error(Eperm);
|
||||
switch(NETTYPE(c->qid.path)){
|
||||
case Qlease:
|
||||
case Qclone:
|
||||
error(Eperm);
|
||||
}
|
||||
|
||||
strs = smalloc(n);
|
||||
if(waserror()){
|
||||
|
@ -261,13 +481,16 @@ srvwstat(Chan *c, uchar *dp, int n)
|
|||
if(n == 0)
|
||||
error(Eshortstat);
|
||||
|
||||
qlock(&srvlk);
|
||||
b = c->aux;
|
||||
wlock(b);
|
||||
if(waserror()){
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
nexterror();
|
||||
}
|
||||
if(b->closed)
|
||||
error(Eexpired);
|
||||
|
||||
sp = srvlookup(nil, c->qid.path);
|
||||
sp = lookup(b->srv, nil, c->qid.path);
|
||||
if(sp == nil)
|
||||
error(Enonexist);
|
||||
|
||||
|
@ -279,6 +502,10 @@ srvwstat(Chan *c, uchar *dp, int n)
|
|||
error(Ebadchar);
|
||||
if(strlen(d.name) >= sizeof(up->genbuf))
|
||||
error(Etoolong);
|
||||
if(lookup(b->srv, d.name, ~0UL) != nil)
|
||||
error(Eexist);
|
||||
if(lookup(b->child, d.name, ~0UL) != nil)
|
||||
error(Eexist);
|
||||
kstrdup(&sp->name, d.name);
|
||||
}
|
||||
if(d.uid != nil && *d.uid)
|
||||
|
@ -286,7 +513,7 @@ srvwstat(Chan *c, uchar *dp, int n)
|
|||
if(d.mode != ~0UL)
|
||||
sp->perm = d.mode & 0777;
|
||||
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
poperror();
|
||||
|
||||
free(strs);
|
||||
|
@ -298,22 +525,47 @@ srvwstat(Chan *c, uchar *dp, int n)
|
|||
static void
|
||||
srvclose(Chan *c)
|
||||
{
|
||||
/*
|
||||
* in theory we need to override any changes in removability
|
||||
* since open, but since all that's checked is the owner,
|
||||
* which is immutable, all is well.
|
||||
*/
|
||||
if(c->flag & CRCLOSE){
|
||||
Board *b;
|
||||
int expired;
|
||||
|
||||
expired = 0;
|
||||
if(NETTYPE(c->qid.path) == Qlease)
|
||||
expired++;
|
||||
else if(c->flag & CRCLOSE){
|
||||
/*
|
||||
* in theory we need to override any changes in removability
|
||||
* since open, but since all that's checked is the owner,
|
||||
* which is immutable, all is well.
|
||||
*/
|
||||
if(waserror())
|
||||
return;
|
||||
goto Clunk;
|
||||
srvremove(c);
|
||||
poperror();
|
||||
return;
|
||||
}
|
||||
Clunk:
|
||||
b = c->aux;
|
||||
wlock(b);
|
||||
boardclunk(b, expired); //unlock
|
||||
}
|
||||
|
||||
static long
|
||||
srvread(Chan *c, void *va, long n, vlong)
|
||||
srvread(Chan *c, void *va, long n, vlong off)
|
||||
{
|
||||
Board *b;
|
||||
|
||||
if(NETTYPE(c->qid.path) == Qlease){
|
||||
b = c->aux;
|
||||
rlock(b);
|
||||
if(waserror()){
|
||||
runlock(b);
|
||||
nexterror();
|
||||
}
|
||||
n = readstr((ulong)off, va, n, b->name);
|
||||
runlock(b);
|
||||
poperror();
|
||||
return n;
|
||||
}
|
||||
isdir(c);
|
||||
return devdirread(c, va, n, 0, 0, srvgen);
|
||||
}
|
||||
|
@ -321,11 +573,15 @@ srvread(Chan *c, void *va, long n, vlong)
|
|||
static long
|
||||
srvwrite(Chan *c, void *va, long n, vlong)
|
||||
{
|
||||
Board *b;
|
||||
Srv *sp;
|
||||
Chan *c1;
|
||||
int fd;
|
||||
char buf[32];
|
||||
|
||||
if(NETTYPE(c->qid.path) == Qlease)
|
||||
error(Eperm);
|
||||
|
||||
if(n >= sizeof buf)
|
||||
error(Etoobig);
|
||||
memmove(buf, va, n); /* so we can NUL-terminate */
|
||||
|
@ -334,15 +590,18 @@ srvwrite(Chan *c, void *va, long n, vlong)
|
|||
|
||||
c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
|
||||
|
||||
qlock(&srvlk);
|
||||
b = c->aux;
|
||||
wlock(b);
|
||||
if(waserror()) {
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
cclose(c1);
|
||||
nexterror();
|
||||
}
|
||||
if(b->closed)
|
||||
error(Eexpired);
|
||||
if(c1->qid.type & QTAUTH)
|
||||
error("cannot post auth file in srv");
|
||||
sp = srvlookup(nil, c->qid.path);
|
||||
sp = lookup(b->srv, nil, c->qid.path);
|
||||
if(sp == nil)
|
||||
error(Enonexist);
|
||||
|
||||
|
@ -351,7 +610,7 @@ srvwrite(Chan *c, void *va, long n, vlong)
|
|||
|
||||
sp->chan = c1;
|
||||
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
poperror();
|
||||
return n;
|
||||
}
|
||||
|
@ -380,12 +639,14 @@ Dev srvdevtab = {
|
|||
void
|
||||
srvrenameuser(char *old, char *new)
|
||||
{
|
||||
Board *b;
|
||||
Srv *sp;
|
||||
|
||||
qlock(&srvlk);
|
||||
for(sp = srv; sp != nil; sp = sp->link) {
|
||||
b = &root;
|
||||
wlock(b);
|
||||
for(sp = b->srv; sp != nil; sp = sp->link) {
|
||||
if(sp->owner != nil && strcmp(old, sp->owner) == 0)
|
||||
kstrdup(&sp->owner, new);
|
||||
}
|
||||
qunlock(&srvlk);
|
||||
wunlock(b);
|
||||
}
|
||||
|
|
384
sys/src/9/port/dtracydev.c
Normal file
384
sys/src/9/port/dtracydev.c
Normal file
|
@ -0,0 +1,384 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
#include <dtracy.h>
|
||||
|
||||
enum{
|
||||
Dwalk,
|
||||
Dstat,
|
||||
Dopen,
|
||||
Dcreate,
|
||||
Dclose,
|
||||
Dread,
|
||||
Dbread,
|
||||
Dwrite,
|
||||
Dbwrite,
|
||||
Dremove,
|
||||
Dwstat,
|
||||
|
||||
Dend
|
||||
};
|
||||
|
||||
static char *optab[] = {
|
||||
[Dwalk] "walk",
|
||||
[Dstat] "stat",
|
||||
[Dopen] "open",
|
||||
[Dcreate] "create",
|
||||
[Dclose] "close",
|
||||
[Dread] "read",
|
||||
[Dbread] "bread",
|
||||
[Dwrite] "write",
|
||||
[Dbwrite] "bwrite",
|
||||
[Dremove] "remove",
|
||||
[Dwstat] "wstat",
|
||||
};
|
||||
|
||||
struct {
|
||||
DTProbe *in[Dend];
|
||||
DTProbe *out[Dend];
|
||||
Dev clean;
|
||||
} ledger[256];
|
||||
|
||||
static Walkqid*
|
||||
wrapwalk(Chan *c, Chan *nc, char **names, int nname)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
Walkqid *wq;
|
||||
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)nc;
|
||||
info.arg[2] = (uvlong)names;
|
||||
info.arg[3] = (uvlong)nname;
|
||||
dtptrigger(ledger[c->type].in[Dwalk], &info);
|
||||
|
||||
wq = ledger[c->type].clean.walk(c, nc, names, nname);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)wq;
|
||||
dtptrigger(ledger[c->type].out[Dwalk], &info);
|
||||
return wq;
|
||||
}
|
||||
|
||||
static int
|
||||
wrapstat(Chan *c, uchar *b, int n)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)b;
|
||||
info.arg[2] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].in[Dstat], &info);
|
||||
|
||||
n = ledger[c->type].clean.stat(c, b, n);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].out[Dstat], &info);
|
||||
return n;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
wrapopen(Chan *c, int mode)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)mode;
|
||||
dtptrigger(ledger[c->type].in[Dopen], &info);
|
||||
|
||||
c = ledger[c->type].clean.open(c, mode);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)c;
|
||||
dtptrigger(ledger[c->type].out[Dopen], &info);
|
||||
return c;
|
||||
}
|
||||
|
||||
static Chan*
|
||||
wrapcreate(Chan *c, char *name, int mode, ulong perm)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)name;
|
||||
info.arg[2] = (uvlong)mode;
|
||||
info.arg[3] = (uvlong)perm;
|
||||
dtptrigger(ledger[c->type].in[Dcreate], &info);
|
||||
|
||||
c = ledger[c->type].clean.create(c, name, mode, perm);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)c;
|
||||
dtptrigger(ledger[c->type].out[Dcreate], &info);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
wrapclose(Chan *c)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
dtptrigger(ledger[c->type].in[Dclose], &info);
|
||||
|
||||
ledger[c->type].clean.close(c);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
dtptrigger(ledger[c->type].out[Dclose], &info);
|
||||
}
|
||||
|
||||
static long
|
||||
wrapread(Chan *c, void *b, long n, vlong off)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)b;
|
||||
info.arg[2] = (uvlong)n;
|
||||
info.arg[3] = (uvlong)off;
|
||||
dtptrigger(ledger[c->type].in[Dread], &info);
|
||||
|
||||
n = ledger[c->type].clean.read(c, b, n, off);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].out[Dread], &info);
|
||||
return n;
|
||||
}
|
||||
|
||||
static Block*
|
||||
wrapbread(Chan *c, long n, ulong off)
|
||||
{
|
||||
Block *b;
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)n;
|
||||
info.arg[2] = (uvlong)off;
|
||||
dtptrigger(ledger[c->type].in[Dbread], &info);
|
||||
|
||||
b = ledger[c->type].clean.bread(c, n, off);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)b;
|
||||
dtptrigger(ledger[c->type].out[Dbread], &info);
|
||||
return b;
|
||||
}
|
||||
|
||||
static long
|
||||
wrapwrite(Chan *c, void *b, long n, vlong off)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)b;
|
||||
info.arg[2] = (uvlong)n;
|
||||
info.arg[3] = (uvlong)off;
|
||||
dtptrigger(ledger[c->type].in[Dwrite], &info);
|
||||
|
||||
n = ledger[c->type].clean.write(c, b, n, off);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].out[Dwrite], &info);
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
wrapbwrite(Chan *c, Block *b, ulong off)
|
||||
{
|
||||
long n;
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)b;
|
||||
info.arg[2] = (uvlong)off;
|
||||
dtptrigger(ledger[c->type].in[Dbwrite], &info);
|
||||
|
||||
n = ledger[c->type].clean.bwrite(c, b, off);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].out[Dbwrite], &info);
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
wrapremove(Chan *c)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
dtptrigger(ledger[c->type].in[Dremove], &info);
|
||||
|
||||
ledger[c->type].clean.remove(c);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
dtptrigger(ledger[c->type].out[Dremove], &info);
|
||||
}
|
||||
|
||||
int
|
||||
wrapwstat(Chan *c, uchar *b, int n)
|
||||
{
|
||||
DTTrigInfo info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[0] = (uvlong)c;
|
||||
info.arg[1] = (uvlong)b;
|
||||
info.arg[2] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].in[Dwstat], &info);
|
||||
|
||||
n = ledger[c->type].clean.wstat(c, b, n);
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.arg[9] = (uvlong)n;
|
||||
dtptrigger(ledger[c->type].out[Dwstat], &info);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
devprovide(DTProvider *prov)
|
||||
{
|
||||
uint i, j;
|
||||
uint path;
|
||||
char pname[32];
|
||||
char buf[32];
|
||||
|
||||
for(i = 0; devtab[i] != nil; i++){
|
||||
memmove(&ledger[i].clean, devtab[i], sizeof(Dev));
|
||||
for(j = 0; j < Dend; j++){
|
||||
path = (i<<16) | j;
|
||||
snprint(buf, sizeof buf, "dev:%s:%s", devtab[i]->name, optab[j]);
|
||||
snprint(pname, sizeof pname, "%s:entry", buf);
|
||||
ledger[i].in[j] = dtpnew(pname, prov, (void *) path);
|
||||
snprint(pname, sizeof pname, "%s:return", buf);
|
||||
ledger[i].out[j] = dtpnew(pname, prov, (void *) path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
devenable(DTProbe *p)
|
||||
{
|
||||
uint i, j;
|
||||
uint path;
|
||||
Dev *d;
|
||||
|
||||
path = (uint)(uintptr)p->aux;
|
||||
i = path>>16;
|
||||
j = path & ((1<<16)-1);
|
||||
assert(i < 256);
|
||||
assert(j < Dend);
|
||||
|
||||
d = devtab[i];
|
||||
switch(j){
|
||||
case Dwalk:
|
||||
d->walk = wrapwalk;
|
||||
break;
|
||||
case Dstat:
|
||||
d->stat = wrapstat;
|
||||
break;
|
||||
case Dopen:
|
||||
d->open = wrapopen;
|
||||
break;
|
||||
case Dcreate:
|
||||
d->create = wrapcreate;
|
||||
break;
|
||||
case Dclose:
|
||||
d->close = wrapclose;
|
||||
break;
|
||||
case Dread:
|
||||
d->read = wrapread;
|
||||
break;
|
||||
case Dbread:
|
||||
d->bread = wrapbread;
|
||||
break;
|
||||
case Dwrite:
|
||||
d->write = wrapwrite;
|
||||
break;
|
||||
case Dbwrite:
|
||||
d->bwrite = wrapbwrite;
|
||||
break;
|
||||
case Dremove:
|
||||
d->remove = wrapremove;
|
||||
break;
|
||||
case Dwstat:
|
||||
d->wstat = wrapwstat;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
devdisable(DTProbe *p)
|
||||
{
|
||||
uint i, j;
|
||||
uint path;
|
||||
Dev *d, *clean;
|
||||
|
||||
path = (uint)(uintptr)p->aux;
|
||||
i = path>>16;
|
||||
j = path & ((1<<16)-1);
|
||||
assert(i < 256);
|
||||
assert(j < Dend);
|
||||
|
||||
d = devtab[i];
|
||||
clean = &ledger[i].clean;
|
||||
switch(j){
|
||||
case Dwalk:
|
||||
d->walk = clean->walk;
|
||||
break;
|
||||
case Dstat:
|
||||
d->stat = clean->stat;
|
||||
break;
|
||||
case Dopen:
|
||||
d->open = clean->open;
|
||||
break;
|
||||
case Dcreate:
|
||||
d->create = clean->create;
|
||||
break;
|
||||
case Dclose:
|
||||
d->close = clean->close;
|
||||
break;
|
||||
case Dread:
|
||||
d->read = clean->read;
|
||||
break;
|
||||
case Dbread:
|
||||
d->bread = clean->bread;
|
||||
break;
|
||||
case Dwrite:
|
||||
d->write = clean->write;
|
||||
break;
|
||||
case Dbwrite:
|
||||
d->bwrite = clean->bwrite;
|
||||
break;
|
||||
case Dremove:
|
||||
d->remove = clean->remove;
|
||||
break;
|
||||
case Dwstat:
|
||||
d->wstat = clean->wstat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DTProvider dtracydevprov = {
|
||||
.name = "dev",
|
||||
.provide = devprovide,
|
||||
.enable = devenable,
|
||||
.disable = devdisable,
|
||||
};
|
|
@ -87,6 +87,8 @@ miireset(Mii* mii)
|
|||
if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
|
||||
return -1;
|
||||
bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
|
||||
if(bmcr == -1)
|
||||
return -1;
|
||||
bmcr |= BmcrR;
|
||||
mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
|
||||
microdelay(1);
|
||||
|
@ -104,6 +106,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
phyno = mii->curphy->phyno;
|
||||
|
||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||
if(bmsr == -1)
|
||||
return -1;
|
||||
if(!(bmsr & BmsrAna))
|
||||
return -1;
|
||||
|
||||
|
@ -113,6 +117,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
anar = mii->curphy->anar;
|
||||
else{
|
||||
anar = mii->mir(mii, phyno, Anar);
|
||||
if(anar == -1)
|
||||
return -1;
|
||||
anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
|
||||
if(bmsr & Bmsr10THD)
|
||||
anar |= Ana10HD;
|
||||
|
@ -133,6 +139,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
|
||||
if(bmsr & BmsrEs){
|
||||
mscr = mii->mir(mii, phyno, Mscr);
|
||||
if(mscr == -1)
|
||||
return -1;
|
||||
mscr &= ~(Mscr1000TFD|Mscr1000THD);
|
||||
if(e != ~0)
|
||||
mscr |= (Mscr1000TFD|Mscr1000THD) & e;
|
||||
|
@ -140,6 +148,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
mscr = mii->curphy->mscr;
|
||||
else{
|
||||
r = mii->mir(mii, phyno, Esr);
|
||||
if(r == -1)
|
||||
return -1;
|
||||
if(r & Esr1000THD)
|
||||
mscr |= Mscr1000THD;
|
||||
if(r & Esr1000TFD)
|
||||
|
@ -148,9 +158,12 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
mii->curphy->mscr = mscr;
|
||||
mii->miw(mii, phyno, Mscr, mscr);
|
||||
}
|
||||
mii->miw(mii, phyno, Anar, anar);
|
||||
if(mii->miw(mii, phyno, Anar, anar) == -1)
|
||||
return -1;
|
||||
|
||||
r = mii->mir(mii, phyno, Bmcr);
|
||||
if(r == -1)
|
||||
return -1;
|
||||
if(!(r & BmcrR)){
|
||||
r |= BmcrAne|BmcrRan;
|
||||
mii->miw(mii, phyno, Bmcr, r);
|
||||
|
@ -175,12 +188,16 @@ miistatus(Mii* mii)
|
|||
* (Read status twice as the Ls bit is sticky).
|
||||
*/
|
||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||
if(bmsr == -1)
|
||||
return -1;
|
||||
if(!(bmsr & (BmsrAnc|BmsrAna))) {
|
||||
// print("miistatus: auto-neg incomplete\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||
if(bmsr == -1)
|
||||
return -1;
|
||||
if(!(bmsr & BmsrLs)){
|
||||
// print("miistatus: link down\n");
|
||||
phy->link = 0;
|
||||
|
@ -190,6 +207,8 @@ miistatus(Mii* mii)
|
|||
phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
|
||||
if(phy->mscr){
|
||||
r = mii->mir(mii, phyno, Mssr);
|
||||
if(r == -1)
|
||||
return -1;
|
||||
if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
|
||||
phy->speed = 1000;
|
||||
phy->fd = 1;
|
||||
|
@ -199,6 +218,8 @@ miistatus(Mii* mii)
|
|||
}
|
||||
|
||||
anlpar = mii->mir(mii, phyno, Anlpar);
|
||||
if(anlpar == -1)
|
||||
return -1;
|
||||
if(phy->speed == 0){
|
||||
r = phy->anar & anlpar;
|
||||
if(r & AnaTXFD){
|
||||
|
|
56
sys/src/9/port/i2c.h
Normal file
56
sys/src/9/port/i2c.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
typedef struct I2Cbus I2Cbus;
|
||||
struct I2Cbus
|
||||
{
|
||||
char *name;
|
||||
int speed;
|
||||
|
||||
void *ctlr;
|
||||
int (*init)(I2Cbus *bus);
|
||||
int (*io)(I2Cbus *bus, uchar *pkt, int olen, int ilen);
|
||||
|
||||
int probed;
|
||||
QLock;
|
||||
};
|
||||
|
||||
typedef struct I2Cdev I2Cdev;
|
||||
struct I2Cdev
|
||||
{
|
||||
I2Cbus *bus;
|
||||
|
||||
int a10;
|
||||
int addr;
|
||||
int subaddr;
|
||||
ulong size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Register busses (controllers) and devices (addresses)
|
||||
*/
|
||||
extern void addi2cbus(I2Cbus *bus);
|
||||
extern void addi2cdev(I2Cdev *dev);
|
||||
|
||||
/*
|
||||
* Look-up busses and devices by name and address
|
||||
*/
|
||||
extern I2Cbus* i2cbus(char *name);
|
||||
extern I2Cdev* i2cdev(I2Cbus *bus, int addr);
|
||||
|
||||
/*
|
||||
* generic I/O
|
||||
*/
|
||||
extern int i2cbusio(I2Cbus *bus, uchar *pkt, int olen, int ilen);
|
||||
extern int i2crecv(I2Cdev *dev, void *data, int len, vlong addr);
|
||||
extern int i2csend(I2Cdev *dev, void *data, int len, vlong addr);
|
||||
|
||||
/*
|
||||
* common I/O for SMbus
|
||||
*/
|
||||
extern int i2cquick(I2Cdev *dev, int rw);
|
||||
extern int i2crecvbyte(I2Cdev *dev);
|
||||
extern int i2csendbyte(I2Cdev *dev, uchar b);
|
||||
extern int i2creadbyte(I2Cdev *dev, ulong addr);
|
||||
extern int i2cwritebyte(I2Cdev *dev, ulong addr, uchar b);
|
||||
extern int i2creadword(I2Cdev *dev, ulong addr);
|
||||
extern int i2cwriteword(I2Cdev *dev, ulong addr, ushort w);
|
||||
extern vlong i2cread32(I2Cdev *dev, ulong addr);
|
||||
extern vlong i2cwrite32(I2Cdev *dev, ulong addr, ulong u);
|
|
@ -88,7 +88,7 @@ devpipe.$O: ../port/netif.h
|
|||
netif.$O: ../port/netif.h
|
||||
devuart.$O: ../port/netif.h
|
||||
devbridge.$O: ../port/netif.h ../ip/ip.h ../ip/ipv6.h
|
||||
devdtracy.$O dtracysys.$O dtracytimer.$O: /sys/include/dtracy.h
|
||||
devdtracy.$O dtracysys.$O dtracytimer.$O dtracydev.$O: /sys/include/dtracy.h
|
||||
devdraw.$O: screen.h /sys/include/draw.h /sys/include/memdraw.h /sys/include/memlayer.h /sys/include/cursor.h
|
||||
devmouse.$O: screen.h /sys/include/draw.h /sys/include/memdraw.h /sys/include/cursor.h
|
||||
swcursor.$O: screen.h /sys/include/draw.h /sys/include/memdraw.h /sys/include/cursor.h
|
||||
|
|
|
@ -162,6 +162,7 @@ struct SDio {
|
|||
void (*iosetup)(int, void*, int, int);
|
||||
void (*io)(int, uchar*, int);
|
||||
char highspeed;
|
||||
char nomultiwrite; /* quirk for usdhc */
|
||||
};
|
||||
|
||||
extern SDio sdio;
|
||||
|
|
|
@ -332,7 +332,7 @@ mmcbio(SDunit *unit, int lun, int write, void *data, long nb, uvlong bno)
|
|||
error(Echange);
|
||||
buf = data;
|
||||
len = unit->secsize;
|
||||
if(Multiblock){
|
||||
if(Multiblock && (!write || !io->nomultiwrite)){
|
||||
b = bno;
|
||||
tries = 0;
|
||||
while(waserror())
|
||||
|
|
2
sys/src/boot/reform/boot.txt
Normal file
2
sys/src/boot/reform/boot.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} ${prefix}9reform.u
|
||||
bootm ${kernel_addr_r}
|
12
sys/src/boot/reform/mkfile
Normal file
12
sys/src/boot/reform/mkfile
Normal file
|
@ -0,0 +1,12 @@
|
|||
FILES=flash.bin boot.scr
|
||||
|
||||
all:V: $FILES
|
||||
|
||||
clean:V:
|
||||
rm -f $FILES
|
||||
|
||||
flash.bin:
|
||||
hget -o flash.bin 'https://source.mnt.re/reform/reform-boundary-uboot/-/jobs/artifacts/v3/raw/flash.bin?job=build'
|
||||
|
||||
boot.scr: boot.txt
|
||||
aux/txt2uimage -o $target $prereq
|
214
sys/src/cmd/auth/box.c
Normal file
214
sys/src/cmd/auth/box.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
|
||||
static int debug;
|
||||
|
||||
static void
|
||||
binderr(char *new, char *old, int flag)
|
||||
{
|
||||
char dash[4] = { '-' };
|
||||
|
||||
if(debug){
|
||||
if(flag & MCREATE){
|
||||
dash[2] = 'c';
|
||||
flag &= ~MCREATE;
|
||||
}
|
||||
switch(flag){
|
||||
case MREPL:
|
||||
dash[0] = ' ';
|
||||
if(dash[2] == 'c')
|
||||
dash[1] = '-';
|
||||
else
|
||||
dash[1] = ' ';
|
||||
break;
|
||||
case MBEFORE:
|
||||
dash[1] = 'b';
|
||||
break;
|
||||
case MAFTER:
|
||||
dash[1] = 'a';
|
||||
break;
|
||||
}
|
||||
fprint(2, "bind %s %s %s\n", dash, new, old);
|
||||
}
|
||||
if(bind(new, old, flag) < 0)
|
||||
sysfatal("bind: %r");
|
||||
}
|
||||
|
||||
static void
|
||||
resolvenames(char **names, int nname)
|
||||
{
|
||||
int i;
|
||||
char buf[8192];
|
||||
int fd;
|
||||
|
||||
fd = open(".", OREAD|OCEXEC);
|
||||
if(fd < 0)
|
||||
sysfatal("could not open .: %r");
|
||||
fd2path(fd, buf, sizeof buf);
|
||||
for(i = 0; i < nname; i++){
|
||||
if(names[i] == nil)
|
||||
continue;
|
||||
cleanname(names[i]);
|
||||
switch(names[i][0]){
|
||||
case '#':
|
||||
case '/':
|
||||
break;
|
||||
default:
|
||||
names[i] = cleanname(smprint("%s/%s", buf, names[i]));
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
sandbox(char **names, int *flags, int nname)
|
||||
{
|
||||
char *parts[32];
|
||||
char rootskel[128];
|
||||
char src[8192], targ[8192], dir[8192], skel[8192];
|
||||
char name[8192];
|
||||
char *newroot;
|
||||
Dir *d;
|
||||
int i, j, n;
|
||||
|
||||
snprint(rootskel, sizeof rootskel, "/mnt/d/newroot.%d", getpid());
|
||||
binderr(rootskel, "/", MBEFORE);
|
||||
|
||||
newroot = rootskel + strlen("/mnt/d");
|
||||
|
||||
for(j = 0; j < nname; j++){
|
||||
if(names[j] == nil)
|
||||
continue;
|
||||
utfecpy(name, &name[sizeof name-1], names[j]);
|
||||
n = gettokens(name, parts, nelem(parts), "/");
|
||||
utfecpy(targ, &targ[sizeof targ-1], newroot);
|
||||
memset(src, 0, sizeof src);
|
||||
for(i = 0; i < n; i++){
|
||||
utfecpy(dir, &dir[sizeof dir-1], targ);
|
||||
snprint(targ, sizeof targ, "%s/%s", targ, parts[i]);
|
||||
snprint(src, sizeof src, "%s/%s", src, parts[i]);
|
||||
d = dirstat(targ);
|
||||
if(d != nil){
|
||||
free(d);
|
||||
continue;
|
||||
}
|
||||
d = dirstat(src);
|
||||
if(d == nil)
|
||||
continue;
|
||||
if(d->mode & DMDIR)
|
||||
snprint(skel, sizeof skel, "/mnt/d/%s", parts[i]);
|
||||
else
|
||||
snprint(skel, sizeof skel, "/mnt/f/%s", parts[i]);
|
||||
free(d);
|
||||
binderr(skel, dir, MBEFORE);
|
||||
}
|
||||
binderr(names[j], targ, flags[j]);
|
||||
}
|
||||
binderr(newroot, "/", MREPL);
|
||||
}
|
||||
|
||||
void
|
||||
skelfs(void)
|
||||
{
|
||||
int p[2];
|
||||
int dfd;
|
||||
|
||||
pipe(p);
|
||||
switch(rfork(RFFDG|RFREND|RFPROC|RFNAMEG)){
|
||||
case -1:
|
||||
sysfatal("fork");
|
||||
case 0:
|
||||
close(p[1]);
|
||||
dup(p[0], 0);
|
||||
dup(p[0], 1);
|
||||
execl("/bin/skelfs", "skelfs", debug > 1 ? "-Di" : "-i", nil);
|
||||
sysfatal("exec /bin/skelfs: %r");
|
||||
}
|
||||
close(p[0]);
|
||||
dfd = dup(p[1], -1);
|
||||
if(mount(p[1], -1, "/mnt/f", MREPL, "file") < 0)
|
||||
sysfatal("/mnt/f mount setup: %r");
|
||||
if(mount(dfd, -1, "/mnt/d", MREPL, "dir") < 0)
|
||||
sysfatal("/mnt/d mount setup: %r");
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage %s: [ -d ] [ -r file ] [ -c dir ] [ -e devs ] cmd args...\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *b;
|
||||
Dir *d;
|
||||
char devs[1024];
|
||||
int dfd;
|
||||
char *parts[256];
|
||||
int mflags[256];
|
||||
int nparts;
|
||||
|
||||
nparts = 0;
|
||||
memset(devs, 0, sizeof devs);
|
||||
ARGBEGIN{
|
||||
case 'D':
|
||||
debug++;
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
case 'r':
|
||||
parts[nparts] = EARGF(usage());
|
||||
mflags[nparts++] = MREPL;
|
||||
break;
|
||||
case 'c':
|
||||
parts[nparts] = EARGF(usage());
|
||||
mflags[nparts++] = MCREATE|MREPL;
|
||||
break;
|
||||
case 'e':
|
||||
snprint(devs, sizeof devs, "%s%s", devs, EARGF(usage()));
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}ARGEND
|
||||
if(argc == 0)
|
||||
usage();
|
||||
|
||||
b = argv[0];
|
||||
d = dirstat(b);
|
||||
if(d == nil){
|
||||
b = smprint("/bin/%s", b);
|
||||
d = dirstat(b);
|
||||
if(d == nil)
|
||||
sysfatal("could not stat %s %r", argv[0]);
|
||||
}
|
||||
free(d);
|
||||
parts[nparts] = b;
|
||||
mflags[nparts++] = MREPL;
|
||||
argv[0] = b;
|
||||
|
||||
rfork(RFNAMEG|RFFDG);
|
||||
skelfs();
|
||||
dfd = open("/dev/drivers", OWRITE|OCEXEC);
|
||||
if(dfd < 0)
|
||||
sysfatal("could not /dev/drivers: %r");
|
||||
|
||||
resolvenames(parts, nparts);
|
||||
sandbox(parts, mflags, nparts);
|
||||
|
||||
if(debug)
|
||||
fprint(2, "chdev %s\n", devs);
|
||||
|
||||
if(devs[0] != '\0'){
|
||||
if(fprint(dfd, "chdev & %s", devs) <= 0)
|
||||
sysfatal("could not write chdev: %r");
|
||||
} else {
|
||||
if(fprint(dfd, "chdev ~") <= 0)
|
||||
sysfatal("could not write chdev: %r");
|
||||
}
|
||||
close(dfd);
|
||||
exec(argv[0], argv);
|
||||
}
|
|
@ -9,6 +9,7 @@ TARG=\
|
|||
asn1dump\
|
||||
asn12rsa\
|
||||
authsrv\
|
||||
box\
|
||||
changeuser\
|
||||
convkeys\
|
||||
cron\
|
||||
|
|
|
@ -43,6 +43,7 @@ TARG=\
|
|||
tablet\
|
||||
timesync\
|
||||
trampoline\
|
||||
txt2uimage\
|
||||
unbflz\
|
||||
usage\
|
||||
write\
|
||||
|
|
108
sys/src/cmd/aux/txt2uimage.c
Normal file
108
sys/src/cmd/aux/txt2uimage.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <flate.h>
|
||||
|
||||
int infd, outfd;
|
||||
ulong dcrc;
|
||||
ulong *tab;
|
||||
uchar buf[65536];
|
||||
|
||||
enum {
|
||||
IH_TYPE_SCRIPT = 6,
|
||||
};
|
||||
|
||||
void
|
||||
put(uchar *p, u32int v)
|
||||
{
|
||||
*p++ = v >> 24;
|
||||
*p++ = v >> 16;
|
||||
*p++ = v >> 8;
|
||||
*p = v;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s a.out\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
block(int n)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = readn(infd, buf, n);
|
||||
if(rc < 0) sysfatal("read: %r");
|
||||
if(rc < n) sysfatal("input file truncated");
|
||||
if(write(outfd, buf, n) < 0) sysfatal("write: %r");
|
||||
dcrc = blockcrc(tab, dcrc, buf, n);
|
||||
}
|
||||
|
||||
void
|
||||
copy(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = sizeof(buf) - 1; i < n; i += sizeof(buf))
|
||||
block(sizeof(buf));
|
||||
i = n & sizeof(buf) - 1;
|
||||
if(i > 0)
|
||||
block(i);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
uchar header[64];
|
||||
char *ofile;
|
||||
Dir *dir;
|
||||
|
||||
ofile = nil;
|
||||
ARGBEGIN {
|
||||
case 'o': ofile = strdup(EARGF(usage())); break;
|
||||
default: usage();
|
||||
} ARGEND;
|
||||
|
||||
if(argc == 0)
|
||||
infd = 0;
|
||||
else {
|
||||
if(argc != 1) usage();
|
||||
infd = open(argv[0], OREAD);
|
||||
if(infd < 0) sysfatal("infd: %r");
|
||||
}
|
||||
dir = dirfstat(infd);
|
||||
if(dir == nil) sysfatal("stat: %r");
|
||||
if(dir->length > 0xFFFFFFFF-8) sysfatal("file too big");
|
||||
if(ofile == nil) ofile = smprint("%s.u", dir->name);
|
||||
outfd = create(ofile, OWRITE|OTRUNC, 0666);
|
||||
if(outfd < 0) sysfatal("create: %r");
|
||||
|
||||
tab = mkcrctab(0xEDB88320);
|
||||
seek(outfd, sizeof(header), 0);
|
||||
put(buf+0, dir->length);
|
||||
put(buf+4, 0);
|
||||
dcrc = blockcrc(tab, 0, buf, 8);
|
||||
if(write(outfd, buf, 8) != 8) sysfatal("write: %r");
|
||||
copy(dir->length);
|
||||
|
||||
memset(header, 0, sizeof(header));
|
||||
put(&header[0], 0x27051956); /* magic */
|
||||
put(&header[8], time(0)); /* time */
|
||||
put(&header[12], 8+dir->length); /* image size */
|
||||
put(&header[16], 0); /* load address */
|
||||
put(&header[20], 0); /* entry point */
|
||||
put(&header[24], dcrc); /* data crc */
|
||||
header[28] = 0;
|
||||
header[29] = 0;
|
||||
header[30] = IH_TYPE_SCRIPT;
|
||||
header[31] = 0; /* compressed = no */
|
||||
|
||||
strncpy((char*)&header[32], dir->name, sizeof(header)-32);
|
||||
put(&header[4], blockcrc(tab, 0, header, sizeof(header)));
|
||||
|
||||
seek(outfd, 0, 0);
|
||||
if(write(outfd, header, sizeof(header)) < sizeof(header)) sysfatal("write: %r");
|
||||
|
||||
exits(nil);
|
||||
}
|
|
@ -54,11 +54,13 @@ static Cell dollar1 = { OCELL, CFLD, nil, "", 0.0, FLD|STR|DONTFREE };
|
|||
|
||||
void recinit(unsigned int n)
|
||||
{
|
||||
assert(n > 0);
|
||||
record = (char *) malloc(n);
|
||||
fields = (char *) malloc(n);
|
||||
fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
|
||||
if (record == nil || fields == nil || fldtab == nil)
|
||||
FATAL("out of space for $0 and fields");
|
||||
record[0] = '\0';
|
||||
fldtab[0] = (Cell *) malloc(sizeof (Cell));
|
||||
*fldtab[0] = dollar0;
|
||||
fldtab[0]->sval = record;
|
||||
|
@ -108,7 +110,7 @@ int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
|
|||
firsttime = 0;
|
||||
initgetrec();
|
||||
}
|
||||
dprint( ("RS=<%s>, FS=<%s>, AARGC=%g, FILENAME=%s\n",
|
||||
dprint( ("RS=<%s>, FS=<%s>, AARGC=%g, FILENAME=%s\n",
|
||||
*RS, *FS, *AARGC, *FILENAME) );
|
||||
if (isrecord) {
|
||||
donefld = 0;
|
||||
|
|
|
@ -1127,8 +1127,9 @@ Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
|
|||
if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
|
||||
goto Free; /* leave alone unless it's a field */
|
||||
if ((y->tval & (STR|NUM)) == (STR|NUM)) {
|
||||
yf = getfval(y);
|
||||
setsval(x, getsval(y));
|
||||
x->fval = getfval(y);
|
||||
x->fval = yf;
|
||||
x->tval |= NUM;
|
||||
}
|
||||
else if (isstr(y))
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
#include "all.h"
|
||||
#include <fcall.h>
|
||||
|
||||
enum { MSIZE = MAXDAT+MAXMSG };
|
||||
|
||||
static int
|
||||
mkmode9p1(ulong mode9p2)
|
||||
|
@ -155,10 +152,10 @@ version(Chan* chan, Fcall* f, Fcall* r)
|
|||
if(chan->protocol != nil || f->msize < 256)
|
||||
return Eversion;
|
||||
|
||||
if(f->msize < MSIZE)
|
||||
if(f->msize < MAXDAT+IOHDRSZ)
|
||||
r->msize = f->msize;
|
||||
else
|
||||
r->msize = MSIZE;
|
||||
r->msize = MAXDAT+IOHDRSZ;
|
||||
|
||||
/*
|
||||
* Should check the '.' stuff here.
|
||||
|
@ -1825,7 +1822,7 @@ serve9p2(Msgbuf* mb)
|
|||
* replies.
|
||||
*/
|
||||
if(convM2S(mb->data, mb->count, &f) != mb->count){
|
||||
fprint(2, "didn't like %d byte message\n", mb->count);
|
||||
fprint(2, "didn't like %ld byte message\n", mb->count);
|
||||
return 0;
|
||||
}
|
||||
type = f.type;
|
||||
|
@ -1921,7 +1918,7 @@ serve9p2(Msgbuf* mb)
|
|||
*/
|
||||
if(chan->msize == 0){
|
||||
r.ename = "Tversion not seen";
|
||||
n = convS2M(&r, rmb->data, MAXMSG);
|
||||
n = convS2M(&r, rmb->data, SMALLBUF);
|
||||
} else {
|
||||
snprint(ename, sizeof(ename), "9p2: convS2M: type %d",
|
||||
type);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <fcall.h>
|
||||
#define Tfile Tfilescsi /* avoid name conflict */
|
||||
#include <disk.h>
|
||||
#undef Tfile
|
||||
|
|
|
@ -711,9 +711,9 @@ cmd_time(int argc, char *argv[])
|
|||
{
|
||||
int i, len;
|
||||
char *cmd;
|
||||
Timet t1, t2;
|
||||
vlong t1, t2;
|
||||
|
||||
t1 = time(nil);
|
||||
t1 = nsec();
|
||||
len = 0;
|
||||
for(i=1; i<argc; i++)
|
||||
len += 1 + strlen(argv[i]);
|
||||
|
@ -724,9 +724,9 @@ cmd_time(int argc, char *argv[])
|
|||
strcat(cmd, argv[i]);
|
||||
}
|
||||
cmd_exec(cmd);
|
||||
t2 = time(nil);
|
||||
t2 = nsec();
|
||||
free(cmd);
|
||||
print("time = %ld ms\n", TK2MS(t2-t1));
|
||||
print("time = %lld ns\n", t2-t1);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "all.h"
|
||||
#include <fcall.h>
|
||||
|
||||
/* 9p2 */
|
||||
int version(Chan*, Fcall*, Fcall*);
|
||||
|
|
|
@ -20,18 +20,10 @@ typedef vlong Devsize; /* in bytes */
|
|||
#define HOWMANY(x, y) (((x)+((y)-1)) / (y))
|
||||
#define ROUNDUP(x, y) (HOWMANY((x), (y)) * (y))
|
||||
|
||||
#define TK2MS(t) (((ulong)(t)*1000)/HZ) /* ticks to ms - beware rounding */
|
||||
#define MS2TK(t) (((ulong)(t)*HZ)/1000) /* ms to ticks - beware rounding */
|
||||
#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
|
||||
|
||||
/* constants that don't affect disk layout */
|
||||
enum {
|
||||
MAXDAT = 8192, /* max allowable data message */
|
||||
MAXMSG = 128, /* max protocol message sans data */
|
||||
|
||||
MB = 1024*1024,
|
||||
|
||||
HZ = 1, /* clock frequency */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -152,8 +144,8 @@ enum {
|
|||
DIRPERBUF = BUFSIZE / sizeof(Dentry),
|
||||
INDPERBUF = BUFSIZE / sizeof(Off),
|
||||
FEPERBUF = (BUFSIZE-sizeof(Super1)-sizeof(Off)) / sizeof(Off),
|
||||
SMALLBUF = MAXMSG,
|
||||
LARGEBUF = MAXMSG+MAXDAT+256,
|
||||
SMALLBUF = 128,
|
||||
LARGEBUF = IOHDRSZ+MAXDAT+256,
|
||||
RAGAP = (300*1024)/BUFSIZE, /* readahead parameter */
|
||||
BKPERBLK = 10,
|
||||
CEPERBK = (BUFSIZE - BKPERBLK*sizeof(Off)) /
|
||||
|
@ -459,7 +451,7 @@ enum {
|
|||
struct Msgbuf
|
||||
{
|
||||
ulong magic;
|
||||
short count;
|
||||
ulong count;
|
||||
short flags;
|
||||
#define LARGE (1<<0)
|
||||
#define FREE (1<<1)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "all.h"
|
||||
#include "io.h"
|
||||
#include <fcall.h> /* 9p2000 */
|
||||
#include <thread.h>
|
||||
|
||||
enum {
|
||||
|
|
|
@ -101,8 +101,6 @@ loop:
|
|||
unlock(&flock);
|
||||
}
|
||||
|
||||
enum { NOFID = (ulong)~0 };
|
||||
|
||||
/*
|
||||
* returns a locked file structure
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,5 @@ Biobuf *prepare(int, char *, char *);
|
|||
void panic(int, char *, ...);
|
||||
void check(Biobuf *, Biobuf *);
|
||||
void change(int, int, int, int);
|
||||
void fileheader(void);
|
||||
void flushchanges(void);
|
||||
|
||||
|
|
|
@ -329,24 +329,16 @@ changeset(int i)
|
|||
return nchanges;
|
||||
}
|
||||
|
||||
void
|
||||
fileheader(void)
|
||||
{
|
||||
if(mode != 'u')
|
||||
return;
|
||||
Bprint(&stdout, "--- %s\n", file1);
|
||||
Bprint(&stdout, "+++ %s\n", file2);
|
||||
}
|
||||
|
||||
void
|
||||
flushchanges(void)
|
||||
{
|
||||
int a, b, c, d, at;
|
||||
int a, b, c, d, at, hdr;
|
||||
int i, j;
|
||||
|
||||
if(nchanges == 0)
|
||||
return;
|
||||
|
||||
|
||||
hdr = 0;
|
||||
for(i=0; i<nchanges; ){
|
||||
j = changeset(i);
|
||||
a = changes[i].a-Lines;
|
||||
|
@ -369,6 +361,11 @@ flushchanges(void)
|
|||
j = nchanges;
|
||||
}
|
||||
if(mode == 'u'){
|
||||
if(!hdr){
|
||||
Bprint(&stdout, "--- %s\n", file1);
|
||||
Bprint(&stdout, "+++ %s\n", file2);
|
||||
hdr = 1;
|
||||
}
|
||||
Bprint(&stdout, "@@ -%d,%d +%d,%d @@\n", a, b-a+1, c, d-c+1);
|
||||
}else{
|
||||
Bprint(&stdout, "%s:", file1);
|
||||
|
|
|
@ -284,7 +284,6 @@ output(void)
|
|||
m = len[0];
|
||||
J[0] = 0;
|
||||
J[m+1] = len[1]+1;
|
||||
fileheader();
|
||||
if (mode != 'e') {
|
||||
for (i0 = 1; i0 <= m; i0 = i1+1) {
|
||||
while (i0 <= m && J[i0] == J[i0-1]+1)
|
||||
|
|
|
@ -177,17 +177,35 @@ fail(char *pack, char *idx, char *msg, ...)
|
|||
exits(buf);
|
||||
}
|
||||
|
||||
void
|
||||
enqueueparent(Objq *q, Object *o)
|
||||
{
|
||||
Object *p;
|
||||
int i;
|
||||
|
||||
if(o->type != GCommit)
|
||||
return;
|
||||
for(i = 0; i < o->commit->nparent; i++){
|
||||
if((p = readobject(o->commit->parent[i])) == nil)
|
||||
continue;
|
||||
qput(q, p, 0);
|
||||
unref(p);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fetchpack(Conn *c)
|
||||
{
|
||||
char buf[Pktmax], *sp[3], *ep;
|
||||
char *packtmp, *idxtmp, **ref;
|
||||
char *packtmp, *idxtmp, **ref, *caps;
|
||||
Hash h, *have, *want;
|
||||
int nref, refsz, first;
|
||||
int i, n, l, req, pfd;
|
||||
int nref, refsz, first, nsent;
|
||||
int i, l, n, req, pfd;
|
||||
vlong packsz;
|
||||
Objset hadobj;
|
||||
Object *o;
|
||||
Objq haveq;
|
||||
Qelt e;
|
||||
|
||||
nref = 0;
|
||||
refsz = 16;
|
||||
|
@ -234,6 +252,7 @@ fetchpack(Conn *c)
|
|||
if(writephase(c) == -1)
|
||||
sysfatal("write: %r");
|
||||
req = 0;
|
||||
caps = " multi_ack";
|
||||
for(i = 0; i < nref; i++){
|
||||
if(hasheq(&have[i], &want[i]))
|
||||
continue;
|
||||
|
@ -241,30 +260,58 @@ fetchpack(Conn *c)
|
|||
unref(o);
|
||||
continue;
|
||||
}
|
||||
n = snprint(buf, sizeof(buf), "want %H\n", want[i]);
|
||||
if(writepkt(c, buf, n) == -1)
|
||||
if(fmtpkt(c, "want %H%s\n", want[i], caps) == -1)
|
||||
sysfatal("could not send want for %H", want[i]);
|
||||
caps = "";
|
||||
req = 1;
|
||||
}
|
||||
flushpkt(c);
|
||||
|
||||
nsent = 0;
|
||||
qinit(&haveq);
|
||||
osinit(&hadobj);
|
||||
/*
|
||||
* We know we have these objects, and we want to make sure that
|
||||
* they end up at the front of the queue. Send the 'have lines'
|
||||
* first, and then enqueue their parents for a second round of
|
||||
* sends.
|
||||
*/
|
||||
for(i = 0; i < nref; i++){
|
||||
if(hasheq(&have[i], &Zhash) || oshas(&hadobj, have[i]))
|
||||
continue;
|
||||
if((o = readobject(have[i])) == nil)
|
||||
sysfatal("missing object we should have: %H", have[i]);
|
||||
if(fmtpkt(c, "have %H", o->hash) == -1)
|
||||
sysfatal("write: %r");
|
||||
enqueueparent(&haveq, o);
|
||||
osadd(&hadobj, o);
|
||||
unref(o);
|
||||
n = snprint(buf, sizeof(buf), "have %H\n", have[i]);
|
||||
if(writepkt(c, buf, n + 1) == -1)
|
||||
sysfatal("could not send have for %H", have[i]);
|
||||
unref(o);
|
||||
}
|
||||
/*
|
||||
* While we could short circuit this and check if upstream has
|
||||
* acked our objects, for the first 256 haves, this is simple
|
||||
* enough.
|
||||
*
|
||||
* Also, doing multiple rounds of reference discovery breaks
|
||||
* when using smart http.
|
||||
*/
|
||||
while(req && qpop(&haveq, &e) && nsent < 256){
|
||||
if(oshas(&hadobj, e.o->hash))
|
||||
continue;
|
||||
if((o = readobject(e.o->hash)) == nil)
|
||||
sysfatal("missing object we should have: %H", have[i]);
|
||||
if(fmtpkt(c, "have %H", o->hash) == -1)
|
||||
sysfatal("write: %r");
|
||||
enqueueparent(&haveq, o);
|
||||
osadd(&hadobj, o);
|
||||
unref(o);
|
||||
nsent++;
|
||||
}
|
||||
osclear(&hadobj);
|
||||
qclear(&haveq);
|
||||
if(!req)
|
||||
flushpkt(c);
|
||||
|
||||
n = snprint(buf, sizeof(buf), "done\n");
|
||||
if(writepkt(c, buf, n) == -1)
|
||||
if(fmtpkt(c, "done\n") == -1)
|
||||
sysfatal("write: %r");
|
||||
if(!req)
|
||||
goto showrefs;
|
||||
|
@ -298,9 +345,9 @@ fetchpack(Conn *c)
|
|||
if(strncmp(buf, "PACK", 4) == 0)
|
||||
break;
|
||||
l = strtol(buf, &ep, 16);
|
||||
if(l == 0 || ep != buf + 4)
|
||||
if(ep != buf + 4)
|
||||
sysfatal("fetch packfile: junk pktline");
|
||||
if(readn(c->rfd, buf, l) != l)
|
||||
if(readn(c->rfd, buf, l-4) != l-4)
|
||||
sysfatal("fetch packfile: short read");
|
||||
}
|
||||
if(write(pfd, "PACK", 4) != 4)
|
||||
|
|
|
@ -313,6 +313,7 @@ Delta* deltify(Object*, Dtab*, int*);
|
|||
/* proto handling */
|
||||
int readpkt(Conn*, char*, int);
|
||||
int writepkt(Conn*, char*, int);
|
||||
int fmtpkt(Conn*, char*, ...);
|
||||
int flushpkt(Conn*);
|
||||
void initconn(Conn*, int, int);
|
||||
int gitconnect(Conn *, char *, char *);
|
||||
|
|
|
@ -78,7 +78,7 @@ fn apply @{
|
|||
rc -c '
|
||||
echo applying $msg | sed 1q
|
||||
date=`{seconds $date}
|
||||
if(! files=`$nl{ape/patch -Ep1 < $diffpath | grep ''^patching file'' | sed ''s/^patching file `(.*)''''/\1/''})
|
||||
if(! files=`$nl{patch -p1 < $diffpath})
|
||||
die ''patch failed''
|
||||
for(f in $files){
|
||||
if(test -e $f)
|
||||
|
|
|
@ -884,6 +884,7 @@ parsecommit(Object *o)
|
|||
}else if(strcmp(buf, "gpgsig") == 0){
|
||||
/* just drop it */
|
||||
if((t = strstr(p, "-----END PGP SIGNATURE-----")) == nil)
|
||||
if((t = strstr(p, "-----END SSH SIGNATURE-----")) == nil)
|
||||
sysfatal("malformed gpg signature");
|
||||
np -= t - p;
|
||||
p = t;
|
||||
|
|
|
@ -93,6 +93,20 @@ writepkt(Conn *c, char *buf, int nbuf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fmtpkt(Conn *c, char *fmt, ...)
|
||||
{
|
||||
char pkt[Pktmax];
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprint(pkt, sizeof(pkt), fmt, ap);
|
||||
n = writepkt(c, pkt, n);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
flushpkt(Conn *c)
|
||||
{
|
||||
|
|
|
@ -8,20 +8,6 @@
|
|||
char *pathpfx = nil;
|
||||
int allowwrite;
|
||||
|
||||
int
|
||||
fmtpkt(Conn *c, char *fmt, ...)
|
||||
{
|
||||
char pkt[Pktmax];
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprint(pkt, sizeof(pkt), fmt, ap);
|
||||
n = writepkt(c, pkt, n);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
showrefs(Conn *c)
|
||||
{
|
||||
|
|
|
@ -64,8 +64,6 @@ int mute, mutestat;
|
|||
int minlease = MinLease;
|
||||
int staticlease = StaticLease;
|
||||
|
||||
uvlong start;
|
||||
|
||||
static int v6opts;
|
||||
|
||||
/* option magic */
|
||||
|
@ -196,15 +194,6 @@ void termopt(Req*);
|
|||
int validip(uchar*);
|
||||
void vectoropt(Req*, int, uchar*, int);
|
||||
|
||||
void
|
||||
timestamp(char *tag)
|
||||
{
|
||||
uvlong t;
|
||||
|
||||
t = nsec()/1000;
|
||||
syslog(0, blog, "%s %lludµs", tag, t - start);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
|
@ -317,7 +306,6 @@ main(int argc, char **argv)
|
|||
n = readlast(r.fd, r.buf, sizeof(r.buf));
|
||||
if(n < Udphdrsize)
|
||||
fatal("error reading requests: %r");
|
||||
start = nsec()/1000;
|
||||
op = optbuf;
|
||||
*op = 0;
|
||||
proto(&r, n);
|
||||
|
@ -409,7 +397,6 @@ proto(Req *rp, int n)
|
|||
dhcp(rp);
|
||||
else
|
||||
bootp(rp);
|
||||
timestamp("done");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1477,6 +1464,7 @@ addrsopt(Req *rp, int t, uchar **ip, int i)
|
|||
while(i-- > 0){
|
||||
if (!isv4(*ip)) {
|
||||
op = seprint(op, oe, " skipping %I ", *ip);
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
v6tov4(rp->p, *ip);
|
||||
|
@ -1688,6 +1676,9 @@ logdhcp(Req *rp)
|
|||
char *p, *e;
|
||||
int i;
|
||||
|
||||
if(!debug)
|
||||
return;
|
||||
|
||||
p = buf;
|
||||
e = buf + sizeof(buf);
|
||||
if(rp->dhcptype > 0 && rp->dhcptype <= Inform)
|
||||
|
@ -1717,13 +1708,15 @@ logdhcp(Req *rp)
|
|||
p = seprint(p, e, ")");
|
||||
|
||||
USED(p);
|
||||
syslog(0, blog, "%s", buf);
|
||||
fprint(2, "%s\n", buf);
|
||||
}
|
||||
|
||||
void
|
||||
logdhcpout(Req *rp, char *type)
|
||||
{
|
||||
syslog(0, blog, "%s(%I->%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s",
|
||||
if(!debug)
|
||||
return;
|
||||
fprint(2, "%s(%I->%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s\n",
|
||||
type, rp->up->laddr, rp->up->raddr, rp->id,
|
||||
rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ enum
|
|||
Tulong,
|
||||
Tvec,
|
||||
Tnames,
|
||||
Tp9addrs,
|
||||
};
|
||||
|
||||
typedef struct Option Option;
|
||||
|
@ -93,6 +94,7 @@ static Option option[256] =
|
|||
[OBircserver] { "irc", Taddrs },
|
||||
[OBstserver] { "st", Taddrs },
|
||||
[OBstdaserver] { "stdar", Taddrs },
|
||||
[OBvendorinfo] { "vendorinfo", Tvec },
|
||||
|
||||
[ODipaddr] { "ipaddr", Taddr },
|
||||
[ODlease] { "lease", Tulong },
|
||||
|
@ -109,6 +111,14 @@ static Option option[256] =
|
|||
[ODtftpserver] { "tftp", Tstr },
|
||||
[ODbootfile] { "bootfile", Tstr },
|
||||
[ODdnsdomain] { "dnsdomain", Tnames },
|
||||
|
||||
[OP9authv4] { "p9authv4", Taddrs },
|
||||
[OP9fsv4] { "p9fsv4", Taddrs },
|
||||
[OP9fs] { "p9fs", Tp9addrs },
|
||||
[OP9auth] { "p9auth", Tp9addrs },
|
||||
[OP9ipaddr] { "p9ipaddr", Tp9addrs },
|
||||
[OP9ipmask] { "p9ipmask", Tp9addrs },
|
||||
[OP9ipgw] { "p9ipgw", Tp9addrs },
|
||||
};
|
||||
|
||||
static uchar defrequested[] = {
|
||||
|
@ -414,7 +424,7 @@ dhcprecv(void)
|
|||
int i, n, type;
|
||||
ulong lease;
|
||||
char err[ERRMAX];
|
||||
uchar buf[8000], vopts[256], taddr[IPaddrlen];
|
||||
uchar buf[8000], vopts[256], taddr[IPaddrlen*2];
|
||||
Bootp *bp;
|
||||
|
||||
memset(buf, 0, sizeof buf);
|
||||
|
@ -544,39 +554,33 @@ dhcprecv(void)
|
|||
/* get plan9-specific options */
|
||||
n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1);
|
||||
if(n > 0 && parseoptions(vopts, n) == 0){
|
||||
if(validip(conf.fs) && Oflag)
|
||||
n = 1;
|
||||
else {
|
||||
n = optgetp9addrs(vopts, OP9fs, conf.fs, 2);
|
||||
if (n == 0)
|
||||
n = optgetaddrs(vopts, OP9fsv4,
|
||||
conf.fs, 2);
|
||||
if(!(Oflag && validip(conf.fs))){
|
||||
n = optgetp9addrs(vopts, OP9fs, taddr, 2);
|
||||
if(n < 2)
|
||||
n += optgetaddrs(vopts, OP9fsv4, taddr + (n * IPaddrlen), 2 - n);
|
||||
memmove(conf.fs, taddr, n * IPaddrlen);
|
||||
}
|
||||
for(i = 0; i < n; i++)
|
||||
DEBUG("fs=%I ", conf.fs + i*IPaddrlen);
|
||||
|
||||
if(validip(conf.auth) && Oflag)
|
||||
n = 1;
|
||||
else {
|
||||
n = optgetp9addrs(vopts, OP9auth, conf.auth, 2);
|
||||
if (n == 0)
|
||||
n = optgetaddrs(vopts, OP9authv4,
|
||||
conf.auth, 2);
|
||||
if(!(Oflag && validip(conf.auth))){
|
||||
n = optgetp9addrs(vopts, OP9auth, taddr, 2);
|
||||
if(n < 2)
|
||||
n += optgetaddrs(vopts, OP9authv4, taddr + (n * IPaddrlen), 2 - n);
|
||||
memmove(conf.auth, taddr, n * IPaddrlen);
|
||||
}
|
||||
for(i = 0; i < n; i++)
|
||||
DEBUG("auth=%I ", conf.auth + i*IPaddrlen);
|
||||
DEBUG("fs=(%I %I) auth=(%I %I)", conf.fs, conf.fs + IPaddrlen, conf.auth , conf.auth + IPaddrlen);
|
||||
|
||||
n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1);
|
||||
if (n > 0)
|
||||
ipmove(conf.laddr, taddr);
|
||||
n = optgetp9addrs(vopts, OP9ipmask, taddr, 1);
|
||||
if (n > 0)
|
||||
ipmove(conf.mask, taddr);
|
||||
n = optgetp9addrs(vopts, OP9ipgw, taddr, 1);
|
||||
if (n > 0)
|
||||
ipmove(conf.gaddr, taddr);
|
||||
DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I",
|
||||
conf.laddr, conf.mask, conf.gaddr);
|
||||
if(!(Oflag && validip(conf.laddr)))
|
||||
if(optgetp9addrs(vopts, OP9ipaddr, taddr, 1))
|
||||
ipmove(conf.laddr, taddr);
|
||||
|
||||
if(!(Oflag && validip(conf.mask)))
|
||||
if(optgetp9addrs(vopts, OP9ipmask, taddr, 1))
|
||||
ipmove(conf.mask, taddr);
|
||||
|
||||
if(!(Oflag && validip(conf.gaddr)))
|
||||
if(optgetp9addrs(vopts, OP9ipgw, taddr, 1))
|
||||
ipmove(conf.gaddr, taddr);
|
||||
|
||||
DEBUG("p9 opt ipaddr=%I ipmask=%M ipgw=%I", conf.laddr, conf.mask, conf.gaddr);
|
||||
}
|
||||
conf.lease = lease;
|
||||
conf.state = Sbound;
|
||||
|
@ -779,8 +783,8 @@ optgetp9addrs(uchar *ap, int op, uchar *ip, int n)
|
|||
slen = strlen(p) + 1;
|
||||
if (parseip(&ip[i*IPaddrlen], p) == -1)
|
||||
fprint(2, "%s: bad address %s\n", argv0, p);
|
||||
DEBUG("got plan 9 option %d addr %I (%s)",
|
||||
op, &ip[i*IPaddrlen], p);
|
||||
DEBUG("got plan 9 option %s addr %I (%s)",
|
||||
option[op].name, &ip[i*IPaddrlen], p);
|
||||
p += slen;
|
||||
len -= slen;
|
||||
}
|
||||
|
|
|
@ -355,6 +355,7 @@ portattach(Hub *h, int p, u32int sts)
|
|||
char *sp;
|
||||
int mp;
|
||||
int nr;
|
||||
int i;
|
||||
|
||||
d = h->dev;
|
||||
pp = &h->port[p];
|
||||
|
@ -421,9 +422,13 @@ portattach(Hub *h, int p, u32int sts)
|
|||
nd->isusb3 = h->dev->isusb3;
|
||||
if(usbdebug > 2)
|
||||
devctl(nd, "debug 1");
|
||||
if(opendevdata(nd, ORDWR) < 0){
|
||||
for(i=0;; i++){
|
||||
if(opendevdata(nd, ORDWR) >= 0)
|
||||
break;
|
||||
fprint(2, "%s: %s: opendevdata: %r\n", argv0, nd->dir);
|
||||
goto Fail;
|
||||
if(i >= 4)
|
||||
goto Fail;
|
||||
sleep(500);
|
||||
}
|
||||
if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
|
||||
dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
|
||||
|
|
611
sys/src/cmd/patch.c
Normal file
611
sys/src/cmd/patch.c
Normal file
|
@ -0,0 +1,611 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <bio.h>
|
||||
|
||||
typedef struct Patch Patch;
|
||||
typedef struct Hunk Hunk;
|
||||
typedef struct Fbuf Fbuf;
|
||||
|
||||
struct Patch {
|
||||
char *name;
|
||||
Hunk *hunk;
|
||||
usize nhunk;
|
||||
};
|
||||
|
||||
struct Hunk {
|
||||
int lnum;
|
||||
|
||||
char *oldpath;
|
||||
int oldln;
|
||||
int oldcnt;
|
||||
int oldlen;
|
||||
int oldsz;
|
||||
char *old;
|
||||
|
||||
char *newpath;
|
||||
int newln;
|
||||
int newcnt;
|
||||
int newlen;
|
||||
int newsz;
|
||||
char *new;
|
||||
};
|
||||
|
||||
struct Fbuf {
|
||||
int *lines;
|
||||
int nlines;
|
||||
int lastln;
|
||||
char *buf;
|
||||
int len;
|
||||
};
|
||||
|
||||
int strip;
|
||||
int reverse;
|
||||
void (*addnew)(Hunk*, char*);
|
||||
void (*addold)(Hunk*, char*);
|
||||
|
||||
char*
|
||||
readline(Biobuf *f, int *lnum)
|
||||
{
|
||||
char *ln;
|
||||
|
||||
if((ln = Brdstr(f, '\n', 0)) == nil)
|
||||
return nil;
|
||||
*lnum += 1;
|
||||
return ln;
|
||||
}
|
||||
|
||||
void *
|
||||
emalloc(ulong n)
|
||||
{
|
||||
void *v;
|
||||
|
||||
v = mallocz(n, 1);
|
||||
if(v == nil)
|
||||
sysfatal("malloc: %r");
|
||||
setmalloctag(v, getcallerpc(&n));
|
||||
return v;
|
||||
}
|
||||
|
||||
void *
|
||||
erealloc(void *v, ulong n)
|
||||
{
|
||||
if(n == 0)
|
||||
n++;
|
||||
v = realloc(v, n);
|
||||
if(v == nil)
|
||||
sysfatal("malloc: %r");
|
||||
setmalloctag(v, getcallerpc(&n));
|
||||
return v;
|
||||
}
|
||||
|
||||
int
|
||||
fileheader(char *s, char *pfx, char **name)
|
||||
{
|
||||
int len, n, nnull;
|
||||
char *e;
|
||||
|
||||
if((strncmp(s, pfx, strlen(pfx))) != 0)
|
||||
return -1;
|
||||
for(s += strlen(pfx); *s; s++)
|
||||
if(!isspace(*s))
|
||||
break;
|
||||
for(e = s; *e; e++)
|
||||
if(isspace(*e))
|
||||
break;
|
||||
if(s == e)
|
||||
return -1;
|
||||
nnull = strlen("/dev/null");
|
||||
if((e - s) != nnull || strncmp(s, "/dev/null", nnull) != 0){
|
||||
n = strip;
|
||||
while(s != e && n > 0){
|
||||
while(s != e && *s == '/')
|
||||
s++;
|
||||
while(s != e && *s != '/')
|
||||
s++;
|
||||
n--;
|
||||
}
|
||||
while(*s == '/')
|
||||
s++;
|
||||
if(*s == '\0')
|
||||
sysfatal("too many components stripped");
|
||||
}
|
||||
len = (e - s) + 1;
|
||||
*name = emalloc(len);
|
||||
strecpy(*name, *name + len, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hunkheader(Hunk *h, char *s, char *oldpath, char *newpath, int lnum)
|
||||
{
|
||||
char *e;
|
||||
|
||||
memset(h, 0, sizeof(*h));
|
||||
h->lnum = lnum;
|
||||
h->oldpath = strdup(oldpath);
|
||||
h->newpath = strdup(newpath);
|
||||
h->oldlen = 0;
|
||||
h->oldsz = 32;
|
||||
h->old = emalloc(h->oldsz);
|
||||
h->newlen = 0;
|
||||
h->newsz = 32;
|
||||
h->new = emalloc(h->newsz);
|
||||
if(strncmp(s, "@@ -", 4) != 0)
|
||||
return -1;
|
||||
e = s + 4;
|
||||
h->oldln = strtol(e, &e, 10);
|
||||
h->oldcnt = 1;
|
||||
if(*e == ','){
|
||||
e++;
|
||||
h->oldcnt = strtol(e, &e, 10);
|
||||
}
|
||||
while(*e == ' ' || *e == '\t')
|
||||
e++;
|
||||
if(*e != '+')
|
||||
return -1;
|
||||
e++;
|
||||
h->newln = strtol(e, &e, 10);
|
||||
if(e == s)
|
||||
return -1;
|
||||
h->newcnt = 1;
|
||||
if(*e == ','){
|
||||
e++;
|
||||
h->newcnt = strtol(e, &e, 10);
|
||||
}
|
||||
if(e == s || *e != ' ')
|
||||
return -1;
|
||||
if(strncmp(e, " @@", 3) != 0)
|
||||
return -1;
|
||||
/*
|
||||
* empty files have line number 0: keep that,
|
||||
* otherwise adjust down.
|
||||
*/
|
||||
if(h->oldln > 0)
|
||||
h->oldln--;
|
||||
if(h->newln > 0)
|
||||
h->newln--;
|
||||
if(h->oldln < 0 || h->newln < 0 || h->oldcnt < 0 || h->newcnt < 0)
|
||||
sysfatal("malformed hunk %s", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
addnewfn(Hunk *h, char *ln)
|
||||
{
|
||||
int n;
|
||||
|
||||
ln++;
|
||||
n = strlen(ln);
|
||||
while(h->newlen + n >= h->newsz){
|
||||
h->newsz *= 2;
|
||||
h->new = erealloc(h->new, h->newsz);
|
||||
}
|
||||
memcpy(h->new + h->newlen, ln, n);
|
||||
h->newlen += n;
|
||||
}
|
||||
|
||||
void
|
||||
addoldfn(Hunk *h, char *ln)
|
||||
{
|
||||
int n;
|
||||
|
||||
ln++;
|
||||
n = strlen(ln);
|
||||
while(h->oldlen + n >= h->oldsz){
|
||||
h->oldsz *= 2;
|
||||
h->old = erealloc(h->old, h->oldsz);
|
||||
}
|
||||
memcpy(h->old + h->oldlen, ln, n);
|
||||
h->oldlen += n;
|
||||
}
|
||||
|
||||
int
|
||||
addmiss(Hunk *h, char *ln, int *nold, int *nnew)
|
||||
{
|
||||
if(ln == nil)
|
||||
return 1;
|
||||
else if(ln[0] != '-' && ln[0] != '+')
|
||||
return 0;
|
||||
if(ln[0] == '-'){
|
||||
addold(h, ln);
|
||||
*nold += 1;
|
||||
}else{
|
||||
addnew(h, ln);
|
||||
*nnew += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
addhunk(Patch *p, Hunk *h)
|
||||
{
|
||||
p->hunk = erealloc(p->hunk, ++p->nhunk*sizeof(Hunk));
|
||||
p->hunk[p->nhunk-1] = *h;
|
||||
}
|
||||
|
||||
int
|
||||
hunkcmp(void *a, void *b)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = strcmp(((Hunk*)a)->oldpath, ((Hunk*)b)->oldpath);
|
||||
if(c != 0)
|
||||
return c;
|
||||
return ((Hunk*)a)->oldln - ((Hunk*)b)->oldln;
|
||||
}
|
||||
|
||||
Patch*
|
||||
parse(Biobuf *f, char *name)
|
||||
{
|
||||
char *ln, *old, *new, **oldp, **newp;
|
||||
int oldcnt, newcnt, lnum;
|
||||
Patch *p;
|
||||
Hunk h;
|
||||
|
||||
ln = nil;
|
||||
lnum = 0;
|
||||
p = emalloc(sizeof(Patch));
|
||||
if(!reverse){
|
||||
oldp = &old;
|
||||
newp = &new;
|
||||
}else{
|
||||
oldp = &new;
|
||||
newp = &old;
|
||||
}
|
||||
comment:
|
||||
free(ln);
|
||||
while((ln = readline(f, &lnum)) != nil){
|
||||
if(strncmp(ln, "--- ", 4) == 0)
|
||||
goto patch;
|
||||
free(ln);
|
||||
}
|
||||
if(p->nhunk == 0)
|
||||
sysfatal("%s: could not find start of patch", name);
|
||||
goto out;
|
||||
|
||||
patch:
|
||||
if(fileheader(ln, "--- ", oldp) == -1)
|
||||
goto comment;
|
||||
free(ln);
|
||||
|
||||
if((ln = readline(f, &lnum)) == nil)
|
||||
goto out;
|
||||
if(fileheader(ln, "+++ ", newp) == -1)
|
||||
goto comment;
|
||||
free(ln);
|
||||
|
||||
if((ln = readline(f, &lnum)) == nil)
|
||||
goto out;
|
||||
hunk:
|
||||
oldcnt = 0;
|
||||
newcnt = 0;
|
||||
if(hunkheader(&h, ln, old, new, lnum) == -1)
|
||||
goto comment;
|
||||
free(ln);
|
||||
|
||||
while(1){
|
||||
if((ln = readline(f, &lnum)) == nil){
|
||||
if(oldcnt != h.oldcnt || newcnt != h.newcnt)
|
||||
sysfatal("%s:%d: malformed hunk", name, lnum);
|
||||
addhunk(p, &h);
|
||||
break;
|
||||
}
|
||||
switch(ln[0]){
|
||||
default:
|
||||
sysfatal("%s:%d: malformed hunk2", name, lnum);
|
||||
goto out;
|
||||
case '-':
|
||||
addold(&h, ln);
|
||||
oldcnt++;
|
||||
break;
|
||||
case '+':
|
||||
addnew(&h, ln);
|
||||
newcnt++;
|
||||
break;
|
||||
case ' ':
|
||||
addold(&h, ln);
|
||||
addnew(&h, ln);
|
||||
oldcnt++;
|
||||
newcnt++;
|
||||
break;
|
||||
}
|
||||
free(ln);
|
||||
if(oldcnt > h.oldcnt || newcnt > h.newcnt)
|
||||
sysfatal("%s:%d: malformed hunk", name, lnum);
|
||||
if(oldcnt < h.oldcnt || newcnt < h.newcnt)
|
||||
continue;
|
||||
|
||||
addhunk(p, &h);
|
||||
if((ln = readline(f, &lnum)) == nil)
|
||||
goto out;
|
||||
if(strncmp(ln, "--- ", 4) == 0)
|
||||
goto patch;
|
||||
if(strncmp(ln, "@@ ", 3) == 0)
|
||||
goto hunk;
|
||||
goto comment;
|
||||
}
|
||||
|
||||
out:
|
||||
qsort(p->hunk, p->nhunk, sizeof(Hunk), hunkcmp);
|
||||
free(old);
|
||||
free(new);
|
||||
free(ln);
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
rename(int fd, char *name)
|
||||
{
|
||||
Dir st;
|
||||
char *p;
|
||||
|
||||
nulldir(&st);
|
||||
if((p = strrchr(name, '/')) == nil)
|
||||
st.name = name;
|
||||
else
|
||||
st.name = p + 1;
|
||||
return dirfwstat(fd, &st);
|
||||
}
|
||||
|
||||
int
|
||||
mkpath(char *path)
|
||||
{
|
||||
char *p, buf[ERRMAX];
|
||||
int f;
|
||||
|
||||
if(*path == '\0')
|
||||
return 0;
|
||||
for(p = strchr(path+1, '/'); p != nil; p = strchr(p+1, '/')){
|
||||
*p = '\0';
|
||||
if(access(path, AEXIST) != 0){
|
||||
if((f = create(path, OREAD, DMDIR | 0777)) == -1){
|
||||
rerrstr(buf, sizeof(buf));
|
||||
if(strstr(buf, "exist") == nil)
|
||||
return -1;
|
||||
}
|
||||
close(f);
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
blat(char *old, char *new, char *o, usize len)
|
||||
{
|
||||
char *tmp;
|
||||
int fd;
|
||||
|
||||
if(strcmp(new, "/dev/null") == 0){
|
||||
if(len != 0)
|
||||
sysfatal("diff modifies removed file");
|
||||
if(remove(old) == -1)
|
||||
sysfatal("removeold %s: %r", old);
|
||||
return;
|
||||
}
|
||||
if(mkpath(new) == -1)
|
||||
sysfatal("mkpath %s: %r", new);
|
||||
if((tmp = smprint("%s.tmp%d", new, getpid())) == nil)
|
||||
sysfatal("smprint: %r");
|
||||
if((fd = create(tmp, OWRITE, 0666)) == -1)
|
||||
sysfatal("open %s: %r", tmp);
|
||||
if(write(fd, o, len) != len)
|
||||
sysfatal("write %s: %r", tmp);
|
||||
if(strcmp(old, new) == 0 && remove(old) == -1)
|
||||
sysfatal("remove %s: %r", old);
|
||||
if(rename(fd, new) == -1)
|
||||
sysfatal("create %s: %r", new);
|
||||
if(close(fd) == -1)
|
||||
sysfatal("close %s: %r", tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
int
|
||||
slurp(Fbuf *f, char *path)
|
||||
{
|
||||
int n, i, fd, sz, len, nlines, linesz;
|
||||
char *buf;
|
||||
int *lines;
|
||||
|
||||
if((fd = open(path, OREAD)) == -1)
|
||||
sysfatal("open %s: %r", path);
|
||||
sz = 8192;
|
||||
len = 0;
|
||||
buf = emalloc(sz);
|
||||
while(1){
|
||||
if(len == sz){
|
||||
sz *= 2;
|
||||
buf = erealloc(buf, sz);
|
||||
}
|
||||
n = read(fd, buf + len, sz - len);
|
||||
if(n == 0)
|
||||
break;
|
||||
if(n == -1)
|
||||
sysfatal("read %s: %r", path);
|
||||
len += n;
|
||||
}
|
||||
|
||||
nlines = 0;
|
||||
linesz = 32;
|
||||
lines = emalloc(linesz*sizeof(int));
|
||||
lines[nlines++] = 0;
|
||||
for(i = 0; i < len; i++){
|
||||
if(buf[i] != '\n')
|
||||
continue;
|
||||
if(nlines+1 == linesz){
|
||||
linesz *= 2;
|
||||
lines = erealloc(lines, linesz*sizeof(int));
|
||||
}
|
||||
lines[nlines++] = i+1;
|
||||
}
|
||||
f->len = len;
|
||||
f->buf = buf;
|
||||
f->lines = lines;
|
||||
f->nlines = nlines;
|
||||
f->lastln = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char*
|
||||
search(Fbuf *f, Hunk *h, char *fname)
|
||||
{
|
||||
int ln, len, off, fuzz, nfuzz, scanning;
|
||||
|
||||
scanning = 1;
|
||||
len = h->oldlen;
|
||||
nfuzz = (f->nlines < 250) ? f->nlines : 250;
|
||||
for(fuzz = 0; scanning && fuzz <= nfuzz; fuzz++){
|
||||
scanning = 0;
|
||||
ln = h->oldln - fuzz;
|
||||
if(ln > f->lastln){
|
||||
off = f->lines[ln];
|
||||
if(off + len > f->len)
|
||||
continue;
|
||||
scanning = 1;
|
||||
if(memcmp(f->buf + off, h->old, h->oldlen) == 0){
|
||||
f->lastln = ln;
|
||||
return f->buf + off;
|
||||
}
|
||||
}
|
||||
ln = h->oldln + fuzz - 1;
|
||||
if(ln <= f->nlines){
|
||||
off = f->lines[ln];
|
||||
if(off + len >= f->len)
|
||||
continue;
|
||||
scanning = 1;
|
||||
if(memcmp(f->buf + off, h->old, h->oldlen) == 0){
|
||||
f->lastln = ln;
|
||||
return f->buf + off;
|
||||
}
|
||||
}
|
||||
}
|
||||
sysfatal("%s:%d: unable to find hunk offset in %s", fname, h->lnum, h->oldpath);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
append(char *o, int *sz, char *s, char *e)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = (e - s);
|
||||
o = erealloc(o, *sz + n);
|
||||
memcpy(o + *sz, s, n);
|
||||
*sz += n;
|
||||
return o;
|
||||
}
|
||||
|
||||
int
|
||||
apply(Patch *p, char *fname)
|
||||
{
|
||||
char *o, *s, *e, *curfile;
|
||||
int i, osz;
|
||||
Hunk *h;
|
||||
Fbuf f;
|
||||
|
||||
e = nil;
|
||||
o = nil;
|
||||
osz = 0;
|
||||
curfile = nil;
|
||||
for(i = 0; i < p->nhunk; i++){
|
||||
h = &p->hunk[i];
|
||||
if(curfile == nil || strcmp(curfile, h->newpath) != 0){
|
||||
if(slurp(&f, h->oldpath) == -1)
|
||||
sysfatal("slurp %s: %r", h->oldpath);
|
||||
curfile = h->newpath;
|
||||
e = f.buf;
|
||||
}
|
||||
s = e;
|
||||
e = search(&f, h, fname);
|
||||
o = append(o, &osz, s, e);
|
||||
o = append(o, &osz, h->new, h->new + h->newlen);
|
||||
e += h->oldlen;
|
||||
if(i+1 == p->nhunk || strcmp(curfile, p->hunk[i+1].newpath) != 0){
|
||||
o = append(o, &osz, e, f.buf + f.len);
|
||||
blat(h->oldpath, h->newpath, o, osz);
|
||||
if(strcmp(h->newpath, "/dev/null") == 0)
|
||||
print("%s\n", h->oldpath);
|
||||
else
|
||||
print("%s\n", h->newpath);
|
||||
osz = 0;
|
||||
}
|
||||
}
|
||||
free(o);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
freepatch(Patch *p)
|
||||
{
|
||||
Hunk *h;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < p->nhunk; i++){
|
||||
h = &p->hunk[i];
|
||||
free(h->oldpath);
|
||||
free(h->newpath);
|
||||
free(h->old);
|
||||
free(h->new);
|
||||
}
|
||||
free(p->hunk);
|
||||
free(p->name);
|
||||
free(p);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-R] [-p nstrip] [patch...]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Biobuf *f;
|
||||
Patch *p;
|
||||
int i;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'p':
|
||||
strip = atoi(EARGF(usage()));
|
||||
break;
|
||||
case 'R':
|
||||
reverse++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}ARGEND;
|
||||
|
||||
if(reverse){
|
||||
addnew = addoldfn;
|
||||
addold = addnewfn;
|
||||
}else{
|
||||
addnew = addnewfn;
|
||||
addold = addoldfn;
|
||||
}
|
||||
if(argc == 0){
|
||||
if((f = Bfdopen(0, OREAD)) == nil)
|
||||
sysfatal("open stdin: %r");
|
||||
if((p = parse(f, "stdin")) == nil)
|
||||
sysfatal("parse patch: %r");
|
||||
if(apply(p, "stdin") == -1)
|
||||
sysfatal("apply stdin: %r");
|
||||
freepatch(p);
|
||||
Bterm(f);
|
||||
}else{
|
||||
for(i = 0; i < argc; i++){
|
||||
if((f = Bopen(argv[i], OREAD)) == nil)
|
||||
sysfatal("open %s: %r", argv[i]);
|
||||
if((p = parse(f, argv[i])) == nil)
|
||||
sysfatal("parse patch: %r");
|
||||
if(apply(p, argv[i]) == -1)
|
||||
sysfatal("apply %s: %r", argv[i]);
|
||||
freepatch(p);
|
||||
Bterm(f);
|
||||
}
|
||||
}
|
||||
exits(nil);
|
||||
}
|
251
sys/src/cmd/skelfs.c
Normal file
251
sys/src/cmd/skelfs.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
#include <thread.h>
|
||||
#include <9p.h>
|
||||
|
||||
typedef struct Skel Skel;
|
||||
struct Skel {
|
||||
char name[64];
|
||||
char mode;
|
||||
};
|
||||
|
||||
static uvlong sessions;
|
||||
static char defmode;
|
||||
|
||||
enum{
|
||||
Qroot,
|
||||
Qdir,
|
||||
Qskel,
|
||||
};
|
||||
|
||||
#define qtype(x) (((ulong)x)&0x1f)
|
||||
#define qsess(x) ((((ulong)x))>>5)
|
||||
#define mkqid(i,t) ((((ulong)i)<<5)|(t))
|
||||
|
||||
static int
|
||||
step(Fid *f, int way, Qid *res, Dir *dp)
|
||||
{
|
||||
Skel *s;
|
||||
int path;
|
||||
char *name;
|
||||
ulong perm;
|
||||
|
||||
s = f->aux;
|
||||
name = s->name;
|
||||
perm = 0550|DMDIR;
|
||||
path = qtype(f->qid.path) + way;
|
||||
if(!name[0] && way > 0)
|
||||
return -1;
|
||||
|
||||
if(path < 0)
|
||||
goto Root;
|
||||
switch(path){
|
||||
Root:
|
||||
case Qroot:
|
||||
name = "/";
|
||||
/* fallthrough */
|
||||
case Qdir:
|
||||
res->type = QTDIR;
|
||||
break;
|
||||
case Qskel:
|
||||
switch(s->mode){
|
||||
case 'd':
|
||||
res->type = QTDIR;
|
||||
break;
|
||||
case 'f':
|
||||
default:
|
||||
res->type = QTFILE;
|
||||
perm = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
res->vers = qsess(f->qid.path);
|
||||
res->path = mkqid(res->vers, path);
|
||||
if(dp){
|
||||
dp->mode = perm;
|
||||
dp->name = estrdup9p(name);
|
||||
dp->uid = estrdup9p("sys");
|
||||
dp->gid = estrdup9p("sys");
|
||||
dp->qid = *res;
|
||||
dp->length = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dirgen(int i, Dir *d, void *a)
|
||||
{
|
||||
Fid *f;
|
||||
Qid q;
|
||||
|
||||
if(i > 0)
|
||||
return -1;
|
||||
f = a;
|
||||
return step(f, 1, &q, d);
|
||||
}
|
||||
|
||||
static void
|
||||
fidclunk(Fid *fid)
|
||||
{
|
||||
free(fid->aux);
|
||||
}
|
||||
|
||||
static char*
|
||||
fsclone(Fid *old, Fid *new, void*)
|
||||
{
|
||||
Skel *s, *s2;
|
||||
|
||||
s = old->aux;
|
||||
s2 = emalloc9p(sizeof *s2);
|
||||
if(s2 == nil)
|
||||
return "out of memory";
|
||||
memset(s2, 0, sizeof *s2);
|
||||
|
||||
s2->mode = s->mode;
|
||||
utfecpy(s2->name, &s2->name[sizeof s2->name-1], s->name);
|
||||
new->aux = s2;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static char*
|
||||
fswalk1(Fid *old, char *name, void*)
|
||||
{
|
||||
Skel *s;
|
||||
|
||||
if(strcmp("..", name) == 0){
|
||||
step(old, -1, &old->qid, nil);
|
||||
return nil;
|
||||
}
|
||||
|
||||
s = old->aux;
|
||||
if(!s->name[0] && qtype(old->qid.path) == Qroot && s->mode != 'e'){
|
||||
utfecpy(s->name, &s->name[sizeof s->name-1], name);
|
||||
old->qid.vers = sessions++;
|
||||
old->qid.path = mkqid(old->qid.vers, qtype(old->qid.path));
|
||||
} else if(strcmp(name, s->name) != 0)
|
||||
return "does not exist";
|
||||
|
||||
if(step(old, 1, &old->qid, nil) < 0)
|
||||
return "does not exist";
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
fswalk(Req *r)
|
||||
{
|
||||
walkandclone(r, fswalk1, fsclone, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsattach(Req *r)
|
||||
{
|
||||
Skel s;
|
||||
Fid root;
|
||||
char *spec;
|
||||
Qid *q;
|
||||
|
||||
spec = r->ifcall.aname;
|
||||
if(spec && spec[0] != '\0')
|
||||
s.mode = spec[0];
|
||||
else
|
||||
s.mode = defmode;
|
||||
|
||||
q = &r->fid->qid;
|
||||
q->vers = sessions++;
|
||||
q->path = mkqid(q->vers, Qroot);
|
||||
q->type = QTDIR;
|
||||
r->ofcall.qid = *q;
|
||||
|
||||
s.name[0] = '\0';
|
||||
root.aux = &s;
|
||||
respond(r, fsclone(&root, r->fid, nil));
|
||||
}
|
||||
|
||||
static void
|
||||
fsstat(Req *r)
|
||||
{
|
||||
Qid q;
|
||||
|
||||
if(step(r->fid, 0, &q, &r->d) < 0)
|
||||
respond(r, "does not exist");
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsread(Req *r)
|
||||
{
|
||||
dirread9p(r, dirgen, r->fid);
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsopen(Req *r)
|
||||
{
|
||||
r->ofcall.mode = r->ifcall.mode;
|
||||
if(r->ifcall.mode != OREAD)
|
||||
respond(r, "permission denied");
|
||||
else
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
Srv fs=
|
||||
{
|
||||
.attach= fsattach,
|
||||
.open= fsopen,
|
||||
.read= fsread,
|
||||
.stat= fsstat,
|
||||
.walk= fswalk,
|
||||
.destroyfid= fidclunk
|
||||
};
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [ -Di ] [ -s service ] [ -t mode ] [ mntpt ]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *s, *mode;
|
||||
int stdio;
|
||||
|
||||
s = nil;
|
||||
stdio = 0;
|
||||
defmode = 'f';
|
||||
ARGBEGIN{
|
||||
case 'D':
|
||||
chatty9p++;
|
||||
break;
|
||||
case 's':
|
||||
s = EARGF(usage());
|
||||
break;
|
||||
case 'i':
|
||||
stdio = 1;
|
||||
break;
|
||||
case 't':
|
||||
mode = EARGF(usage());
|
||||
defmode = mode[0];
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
if(argc > 1)
|
||||
usage();
|
||||
|
||||
if(stdio == 0){
|
||||
postmountsrv(&fs, s, argc ? argv[0] : "/mnt/skel", MREPL);
|
||||
exits(nil);
|
||||
}
|
||||
fs.infd = 0;
|
||||
fs.outfd = 1;
|
||||
srv(&fs);
|
||||
exits(nil);
|
||||
}
|
|
@ -4,17 +4,14 @@
|
|||
Rune*
|
||||
runestrchr(Rune *s, Rune c)
|
||||
{
|
||||
Rune c0 = c;
|
||||
Rune c1;
|
||||
Rune r;
|
||||
|
||||
if(c == 0) {
|
||||
if(c == 0)
|
||||
while(*s++)
|
||||
;
|
||||
return s-1;
|
||||
}
|
||||
|
||||
while(c1 = *s++)
|
||||
if(c1 == c0)
|
||||
return s-1;
|
||||
return 0;
|
||||
else
|
||||
while((r = *s++) != c)
|
||||
if(r == 0)
|
||||
return 0;
|
||||
return s-1;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,14 @@
|
|||
char*
|
||||
strchr(char *s, int c)
|
||||
{
|
||||
char c0 = c;
|
||||
char c1;
|
||||
char r;
|
||||
|
||||
if(c == 0) {
|
||||
if(c == 0)
|
||||
while(*s++)
|
||||
;
|
||||
return s-1;
|
||||
}
|
||||
|
||||
while(c1 = *s++)
|
||||
if(c1 == c0)
|
||||
return s-1;
|
||||
return 0;
|
||||
else
|
||||
while((r = *s++) != c)
|
||||
if(r == 0)
|
||||
return 0;
|
||||
return s-1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue