Merge branch 'front' of git://git.9front.org/plan9front/plan9front into front

This commit is contained in:
xfnw 2022-06-29 12:08:10 -04:00
commit 58fe4bd42c
72 changed files with 7965 additions and 279 deletions

View file

@ -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.

View file

@ -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
View file

@ -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
View 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.

View file

@ -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
View 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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -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
View 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
View 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
View 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);
}

View file

@ -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

File diff suppressed because it is too large Load diff

911
sys/src/9/imx8/lcd.c Normal file
View 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);
}

View file

@ -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);

View file

@ -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)

View file

@ -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

View file

@ -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);
}

View file

@ -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
View 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
View 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);

View file

@ -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);
}

View file

@ -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
View 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,
};

View file

@ -147,6 +147,7 @@ misc
dtracysys
dtracytimer
dtracydev
ip
tcp

View file

@ -144,6 +144,7 @@ misc
dtracysys
dtracytimer
dtracydev
ip
tcp

View file

@ -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
View 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,
};

View file

@ -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;

View file

@ -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
View 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,
};

View file

@ -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
View 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);

View file

@ -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

View file

@ -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;

View file

@ -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())

View file

@ -0,0 +1,2 @@
load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} ${prefix}9reform.u
bootm ${kernel_addr_r}

View 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
View 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);
}

View file

@ -9,6 +9,7 @@ TARG=\
asn1dump\
asn12rsa\
authsrv\
box\
changeuser\
convkeys\
cron\

View file

@ -43,6 +43,7 @@ TARG=\
tablet\
timesync\
trampoline\
txt2uimage\
unbflz\
usage\
write\

View 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);
}

View file

@ -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;

View file

@ -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))

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -1,5 +1,4 @@
#include "all.h"
#include <fcall.h>
/* 9p2 */
int version(Chan*, Fcall*, Fcall*);

View file

@ -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)

View file

@ -1,6 +1,5 @@
#include "all.h"
#include "io.h"
#include <fcall.h> /* 9p2000 */
#include <thread.h>
enum {

View file

@ -101,8 +101,6 @@ loop:
unlock(&flock);
}
enum { NOFID = (ulong)~0 };
/*
* returns a locked file structure
*/

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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 *);

View file

@ -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)

View file

@ -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;

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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
View 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
View 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);
}

View file

@ -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;
}

View file

@ -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;
}