diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2022-10-08 10:38:14 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2022-10-08 10:38:14 +0000 |
commit | 166e8b3cf8d2e087258eb47fdba7e890d6a8432a (patch) | |
tree | da16c7d2198956abacd36cb99a6137136503a11e | |
parent | 2a29b497f215f91d05b6718a0e852e8a9b6ce6da (diff) | |
parent | c6ae349e9d67ef24ce429f699c5232a9acdcb1ea (diff) |
merge
36 files changed, 815 insertions, 1282 deletions
diff --git a/lib/font/bit/vga/unicode.font b/lib/font/bit/vga/unicode.font index 5583316ae..65717e30d 100644 --- a/lib/font/bit/vga/unicode.font +++ b/lib/font/bit/vga/unicode.font @@ -71,6 +71,8 @@ 0x2329 0x232a vga.2329-232A 0x239b 0x23bd vga.239B-23BD 0x23ce 0x23ce vga.23CE-23CE +0x23ed 0x23ef vga.23ED-23EF +0x23f4 0x23fa vga.23F4-23FA 0x2409 0x240d vga.2409-240D 0x2423 0x2424 vga.2423-2424 0x2426 0x2426 vga.2426-2426 diff --git a/lib/font/bit/vga/vga.23ED-23EF b/lib/font/bit/vga/vga.23ED-23EF Binary files differnew file mode 100644 index 000000000..3e548652e --- /dev/null +++ b/lib/font/bit/vga/vga.23ED-23EF diff --git a/lib/font/bit/vga/vga.23F4-23FA b/lib/font/bit/vga/vga.23F4-23FA Binary files differnew file mode 100644 index 000000000..b7b7ed542 --- /dev/null +++ b/lib/font/bit/vga/vga.23F4-23FA diff --git a/lib/font/bit/vga/vga.font b/lib/font/bit/vga/vga.font index cb513643e..fce0c8782 100644 --- a/lib/font/bit/vga/vga.font +++ b/lib/font/bit/vga/vga.font @@ -71,6 +71,8 @@ 0x2329 0x232A vga.2329-232A 0x239B 0x23BD vga.239B-23BD 0x23CE 0x23CE vga.23CE-23CE +0x23ED 0x23EF vga.23ED-23EF +0x23F4 0x23FA vga.23F4-23FA 0x2409 0x240D vga.2409-240D 0x2423 0x2424 vga.2423-2424 0x2426 0x2426 vga.2426-2426 diff --git a/sys/include/keyboard.h b/sys/include/keyboard.h index db4a279a0..d95374797 100644 --- a/sys/include/keyboard.h +++ b/sys/include/keyboard.h @@ -44,6 +44,16 @@ enum { Kscrolloneup= KF|0x20, Kscrollonedown= KF|0x21, + /* multimedia keys - no refunds */ + Ksbwd= KF|0x22, /* skip backwards */ + Ksfwd= KF|0x23, /* skip forward */ + Kpause= KF|0x24, /* play/pause */ + Kvoldn= KF|0x25, /* volume decrement */ + Kvolup= KF|0x26, /* volume increment */ + Kmute= KF|0x27, /* (un)mute */ + Kbrtdn= KF|0x28, /* brightness decrement */ + Kbrtup= KF|0x29, /* brightness increment */ + Ksoh= 0x01, Kstx= 0x02, Ketx= 0x03, diff --git a/sys/lib/git/common.rc b/sys/lib/git/common.rc index 1b8172f98..dd434265a 100644 --- a/sys/lib/git/common.rc +++ b/sys/lib/git/common.rc @@ -61,6 +61,7 @@ fn whoami{ name=$user if(~ $email '') email=$user@$sysname + status='' } # merge1 out ours base theirs diff --git a/sys/lib/kbmap/us b/sys/lib/kbmap/us index 75b259426..3877e3c7e 100644 --- a/sys/lib/kbmap/us +++ b/sys/lib/kbmap/us @@ -270,8 +270,8 @@ 2 13 0 2 14 0 2 15 0 -2 16 0 -2 17 0 +2 16 0xf022 +2 17 0xf028 2 18 0 2 19 0 2 20 0 @@ -279,16 +279,16 @@ 2 22 0 2 23 0 2 24 0 -2 25 0 -2 26 0 +2 25 0xf023 +2 26 0xf029 2 27 0 2 28 ^J 2 29 0xf862 2 30 0 2 31 0 -2 32 0 +2 32 0xf027 2 33 0 -2 34 0 +2 34 0xf024 2 35 0 2 36 0 2 37 0 @@ -300,9 +300,9 @@ 2 43 0 2 44 0 2 45 0 -2 46 0 +2 46 0xf025 2 47 0 -2 48 0 +2 48 0xf026 2 49 0 2 50 0 2 51 0 diff --git a/sys/man/1/bar b/sys/man/1/bar index cc0f8f588..1a444a94b 100644 --- a/sys/man/1/bar +++ b/sys/man/1/bar @@ -55,7 +55,7 @@ option. Date and time format may be set using .I -d option, see -.I tmdate(2). +.IR tmdate (2). .SH EXAMPLES An example of how .I bar diff --git a/sys/man/1/camv b/sys/man/1/camv index 3587d712b..ec6ab4eba 100644 --- a/sys/man/1/camv +++ b/sys/man/1/camv @@ -1,16 +1,55 @@ .TH CAMV 1 .SH NAME -camv, camera display +camv \- USB camera display .SH SYNOPSIS -.B camv cam-device +.B camv +.I cam-device .SH DESCRIPTION .I Camv -uses the underlying +uses the .I cam-device -file system to start a graphical camera display stream. +file tree provided by +.IR nusb (4) +to use and control a USB camera. +It opens the tree's +.I video +file to play the video stream directly in the window. .PP -The file system is initialized using nusb/cam (see nusb(4)). +The middle mouse button menu shows and allows editing the current picture settings. +While it lists resolution, format and framerate per second, +those must be set manually before starting +.IR camv (1). +One can quit the program from the right mouse button menu. +.SH EXAMPLES +Initialize and configure a camera before starting +.I camv +in its own window. +.IP +.EX +% nusb/cam 5 +% window -dx 320 -dy 240 \\ + 'label cam + cat <<EOF >/dev/cam5.1/ctl +format 320x240 +fps 30 +backlight-compensation 1 +brightness 20 +contrast 95 +saturation 40 +sharpness 7 +gamma 200 +EOF + camv /dev/cam5.1 +\' +.EE .SH SOURCE .B /sys/src/cmd/camv.c -.SH SEE ALSO +.SH "SEE ALSO" .IR nusb (4) +.SH HISTORY +.I Camv +first appeared in 9front (March, 2018). +.SH BUGS +Not all available picture settings can be set while +.IR camv (1) +is running, some possibly not at all. diff --git a/sys/man/1/chdev b/sys/man/1/chdev index a97df2c4b..cc402543d 100644 --- a/sys/man/1/chdev +++ b/sys/man/1/chdev @@ -81,12 +81,6 @@ then remove the ability to create more: bind '#|' /n/pipe chdev -r '|' .EE -.SH DIAGNOSTICS -.I Chdev -is implemented through writes to -.BR /dev/drivers , -served by -.IR cons (3). .SH SOURCE .B /rc/bin/chdev .SH "SEE ALSO" @@ -95,5 +89,11 @@ for a list of current drivers. .PP .IR intro (3), .IR cons (3) +.SH DIAGNOSTICS +.I Chdev +is implemented through writes to +.BR /dev/drivers , +served by +.IR cons (3). .SH HISTORY Chdev first appeared in 9front (May, 2022). diff --git a/sys/man/1/git b/sys/man/1/git index 79fd64689..32195b2b2 100644 --- a/sys/man/1/git +++ b/sys/man/1/git @@ -291,11 +291,6 @@ When passed the option, the changes are pulled from .I upstream instead of the configured origin. -when passed the -.B -b -.I branch -option, it only pulls changes related to -.IR branch . .PP .B Git/serve diff --git a/sys/man/1/ktrans b/sys/man/1/ktrans index 88f60471e..99b6b4039 100644 --- a/sys/man/1/ktrans +++ b/sys/man/1/ktrans @@ -85,15 +85,6 @@ Korean mode. Implicit layer converts latin to Korean Hangul. .TP .B ctrl-v Vietnamese Telex input. -.SH SOURCE -.B /sys/src/cmd/ktrans -.SH SEE ALSO -.IR rio (4) -.IR kbdfs (8) -.br -.IR /sys/src/cmd/ktrans/README.kenji -.br -.IR /sys/src/cmd/ktrans/READMEJ.kenji .SH EXAMPLES To type the following Japanese text: @@ -112,6 +103,15 @@ nakanakatanoshiImonodesu.[\\n] where [^\\] and [^l] indicate 'ctl-\\' and 'ctl-l', respectively. See README.kenji for the details of this Japanese input method. +.SH SOURCE +.B /sys/src/cmd/ktrans +.SH SEE ALSO +.IR rio (4) +.IR kbdfs (8) +.br +.IR /sys/src/cmd/ktrans/README.kenji +.br +.IR /sys/src/cmd/ktrans/READMEJ.kenji .SH BUGS .PP There is no way to generate the control characters literally. diff --git a/sys/man/1/reform b/sys/man/1/reform index a4e9accf7..b6afac6f0 100644 --- a/sys/man/1/reform +++ b/sys/man/1/reform @@ -109,9 +109,14 @@ Returns attached battery array statistics in the same manner as .B cputemp Exposes the current temperature reading of the CPU. .TP +.B kbdoled +An image can be displayed on the keyboard OLED by writing a 126x32x1 +uncompressed Plan 9 image (with or without a header). Zero-length +write clears the display. +.TP .B light Provides a way to control the backlight of the built-in LCD by -writing \fIlcd [-+]N\fR, +writing \fIlcd [-+]N\fR or \fIkbd [-+]N\fR, where .I N is expressed in percentage, either as an absolute value (0-100) or @@ -145,20 +150,21 @@ to function: reform/shortcuts </dev/kbdtap >/dev/kbdtap .EE .PP -.I Super+F1/F2 +.I Hyper+F1/F2 decreases/increases LCD brightness, -.I Super+F3/F4 -decreases/increases "master" volume, -.I Super+Escape -(un)mutes the audio. -Optionally, a single step amount can be set with +.I Hyper+F7/F8/F9 +skips to the previous track, (un)pauses or skips to the next track in +.IR zuke (1), +.I Hyper+F10 +(un)mutes the audio, +.I Hyper+F11/F12 +decreases/increases "master" volume. Optionally, a single step amount +can be set with .I -l for LCD light level (default is 5) and .I -v for volume (default is 3). Values can be negative to essentially swap -.I F1 -with -.IR F2 . +the decrement and increment keys. .SH SOURCE .B /sys/src/cmd/reform .SH SEE ALSO @@ -173,8 +179,9 @@ recording is not implemented. .B Light was chosen as a shorter alternative to .BR brightness . -In the future it might support controlling keyboard and trackball -light levels. +.PP +Current keyboard light level reading is only an indication, there is +no way to get the actual value from the keyboard. .PP Values displayed in the .B battery diff --git a/sys/man/1/riow b/sys/man/1/riow index df5ec7a1f..b49f99603 100644 --- a/sys/man/1/riow +++ b/sys/man/1/riow @@ -9,7 +9,7 @@ riow \- keyboard-controller for rio(1) .SH DESCRIPTION .I riow provides keyboard controlling for -.I rio(1) +.IR rio (1) in the manner of .IR i3 , .I sway @@ -18,13 +18,9 @@ and so on. It does so by working with (see \fIrio\fR(4)) and .IR /dev/wsys . .SS Running +Example of running .I riow -filters all key combinations that include -.B Kmod4 -modifier, so it has to be placed -.I last -in the chain of programs using -.IR /dev/kbdtap : +with other programs handling input: .EX </dev/kbdtap ktrans | \\ reform/shortcuts | \\ @@ -56,7 +52,7 @@ option. .TP .B Kmod4+enter Spawn a new -.IR window(1) . +.IR window (1). .TP .B Kmod4+h/j/k/l Focus left/down/up/right. diff --git a/sys/man/2/rsa b/sys/man/2/rsa index b44f18bd6..c72105752 100644 --- a/sys/man/2/rsa +++ b/sys/man/2/rsa @@ -62,7 +62,7 @@ RSApub* rsaprivtopub(RSApriv*) RSApub* X509toRSApub(uchar *cert, int ncert, char *name, int nname) .PP .B -RSApub* X509reqtoRSApub(uchar *req, int nreq, char *name*, int nname) +RSApub* X509reqtoRSApub(uchar *req, int nreq, char *name, int nname) .PP .B RSApriv* asn1toRSApriv(uchar *priv, int npriv) diff --git a/sys/man/4/nusb b/sys/man/4/nusb index 72ba89cd3..4b69a98ff 100644 --- a/sys/man/4/nusb +++ b/sys/man/4/nusb @@ -145,8 +145,12 @@ to let .IR kbdfs (8) process them. Mouse events are sent to -.BR /dev/mousein +.B /dev/mousein in the same way. +A file +.BI /dev/hid N ctl +supports setting keyboard repeat and delay setting, the unit is +milliseconds. .SS Joysticks .I Joy parses data packets from a given endpoint and prints back @@ -271,11 +275,34 @@ compatible with .IR audio (3). .SS Camera devices .I Cam -configures and manages a USB camera device. -It implements a file system (normally seen under -.BR /dev ), -compatible with -.IR camv (1). +configures and exposes a USB camera device's capabilities, +implementing a file system compatible with +.IR camv (1), +under a directory named +.BI cam N [. M ]. +It provides the following files: +.BR desc , +showing all of the device's internal descriptors and their values; +.BR format , +listing admissible image resolutions and framerates; +.BR ctl , +the picture settings control file; +.BR frame , +which captures and outputs a single video frame as an +.IR image (6) +file; +and +.IR video , +streaming video in a preset format, resolution and framerate. +In particular, reading from the +.B ctl +file yields a space-separated list of parameter settings, +where the second and third columns correspond to key-value pairs, +and an optional fourth column corresponds to the range of possible numerical values +(formatted as +.IR minimum / increment / maximum ). +The same pairs can be written to the file to configure the camera. +Currently, only the YUY2 video format is supported. .SH SOURCE .B /sys/src/cmd/nusb .SH "SEE ALSO" @@ -288,11 +315,15 @@ compatible with .IR uart (3), .IR usb (3), .IR shr (3), +.IR image (6), .IR nusbrc (8), .IR kbdfs (8) .SH HISTORY .I Joy first appeared in 9front (March, 2014). +.br +.I Cam +first appeared in 9front (March, 2018). .SH BUGS The various device drivers are generic USB drivers and may work only for certain devices of each class. @@ -307,3 +338,9 @@ and signals and some of the extra features are not implemented. For Ftdi, only the Sheevaplug and Guruplug have been tried. There is support for the EHCI debug port, but it loses bytes. +.PP +USB video format settings cannot be changed while +.IR camv (1) +is running, and must be set manually by writing them to +.IR cam (4)'s ctl +file before starting the viewer. diff --git a/sys/man/6/authsrv b/sys/man/6/authsrv index 08342885a..1e835934a 100644 --- a/sys/man/6/authsrv +++ b/sys/man/6/authsrv @@ -593,8 +593,8 @@ and .IR attach (5)). Other services, such as .IR rcpu (1), -.IR rexport(1), -.IR rimport(1) +.IR rexport (1), +.IR rimport (1) and .IR tlssrv (8) run diff --git a/sys/man/8/acmed b/sys/man/8/acmed index 7eb924316..ec094bd17 100644 --- a/sys/man/8/acmed +++ b/sys/man/8/acmed @@ -144,7 +144,7 @@ auth/rsa2jwk acct.key > /sys/lib/tls/acmed/me@example.com.pub Then the .B acct.key must be loaded into -.IR factotum(4). +.IR factotum (4). It is recommended to put .B acct.key into @@ -173,7 +173,7 @@ for more examples on how to use RSA keys. .PP The certificate for the domain can now be fetched. This requires -.IR webfs(4) +.IR webfs (4) to be mounted as the ACME protocol uses HTTP to talk to the provider. .IP diff --git a/sys/man/8/sol b/sys/man/8/sol index 58ecf057f..64ffd8fda 100644 --- a/sys/man/8/sol +++ b/sys/man/8/sol @@ -47,7 +47,7 @@ The flag connects to the VNC port instead. .SH EXAMPLE Connect to the KVM port with -.IR vnc(1): +.IR vnc (1): .IP .EX execnet && vncv 'exec!ip/sol -k host' diff --git a/sys/src/cmd/aux/kbdfs/kbdfs.c b/sys/src/cmd/aux/kbdfs/kbdfs.c index c0b87b2bf..cc2d3c389 100644 --- a/sys/src/cmd/aux/kbdfs/kbdfs.c +++ b/sys/src/cmd/aux/kbdfs/kbdfs.c @@ -124,12 +124,16 @@ Channel *kbdchan; /* chan(char*) */ Channel *intchan; /* chan(int) */ /* - * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard. - * A 'standard' keyboard doesn't produce anything above 0x58. + * The codes at 0x79 and 0x7b are for the (無)変換 "(Mu)henkan" keys + * used by OADG 109(A) keyboards. The PFU Happy Hacking keyboard + * has only one layout and will produce these for otherwise unmarked + * keys. The default mappings for the HHKB on other systems map + * these to Kdown and Kup. The jp kbmap will instead map these + * (along with 0x70) to control characters that ktrans understands. */ Rune kbtab[Nscan] = { -[0x00] 0, 0x1b, '1', '2', '3', '4', '5', '6', +[0x00] 0, Kesc, '1', '2', '3', '4', '5', '6', [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', [0x18] 'o', 'p', '[', ']', '\n', Kctl, 'a', 's', @@ -149,7 +153,7 @@ Rune kbtab[Nscan] = Rune kbtabshift[Nscan] = { -[0x00] 0, 0x1b, '!', '@', '#', '$', '%', '^', +[0x00] 0, Kesc, '!', '@', '#', '$', '%', '^', [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', [0x18] 'O', 'P', '{', '}', '\n', Kctl, 'A', 'S', @@ -171,11 +175,11 @@ Rune kbtabesc1[Nscan] = { [0x00] 0, 0, 0, 0, 0, 0, 0, 0, [0x08] 0, 0, 0, 0, 0, 0, 0, 0, -[0x10] 0, 0, 0, 0, 0, 0, 0, 0, -[0x18] 0, 0, 0, 0, '\n', Kctl, 0, 0, -[0x20] 0, 0, 0, 0, 0, 0, 0, 0, -[0x28] 0, 0, 0, 0, 0, 0, 0, 0, -[0x30] 0, 0, 0, 0, 0, '/', 0, Kprint, +[0x10] Ksbwd, Kbrtdn, 0, 0, 0, 0, 0, 0, +[0x18] 0, Ksfwd, Kbrtup, 0, '\n', Kctl, 0, 0, +[0x20] Kmute, 0, Kpause, 0, 0, 0, 0, 0, +[0x28] 0, 0, 0, 0, 0, 0, Kvoldn, 0, +[0x30] Kvolup, 0, 0, 0, 0, '/', 0, Kprint, [0x38] Kaltgr, 0, 0, 0, 0, 0, 0, 0, [0x40] 0, 0, 0, 0, 0, 0, Kbreak, Khome, [0x48] Kup, Kpgup, 0, Kleft, 0, Kright, 0, Kend, diff --git a/sys/src/cmd/bar.c b/sys/src/cmd/bar.c index 2db493319..1157ad245 100644 --- a/sys/src/cmd/bar.c +++ b/sys/src/cmd/bar.c @@ -200,9 +200,9 @@ auxproc(void *c) Binit(&b, 0, OREAD); for(;;){ s = Brdstr(&b, '\n', 1); - sendp(c, s ? s : strdup("")); if(s == nil) break; + sendp(c, s); } Bterm(&b); diff --git a/sys/src/cmd/cc/pickle.c b/sys/src/cmd/cc/pickle.c index 1946b4e6c..7cac68421 100644 --- a/sys/src/cmd/cc/pickle.c +++ b/sys/src/cmd/cc/pickle.c @@ -172,9 +172,9 @@ pickletype(Type *t) int n; char *an; - if(!debug['P']) + if(!debug['Z']) return; - if(debug['P'] > 1) { + if(debug['Z'] > 1) { n = 0; for(i=iostack; i; i=i->link) n++; @@ -221,9 +221,9 @@ picklevar(Sym *s) Type *t; Sym *s1, *s2; - if(!debug['P'] || debug['s']) + if(!debug['Z'] || debug['s']) return; - if(debug['P'] > 1) { + if(debug['Z'] > 1) { n = 0; for(i=iostack; i; i=i->link) n++; diff --git a/sys/src/cmd/git/compat b/sys/src/cmd/git/compat index f61ff71e9..5058b407c 100644 --- a/sys/src/cmd/git/compat +++ b/sys/src/cmd/git/compat @@ -6,10 +6,8 @@ opts=() args=() fn cmd_init{ - while(~ $#* 0){ + while(! ~ $#* 0){ switch($1){ - case --bare - opts=(-b) case -- # go likes to use these case -* @@ -19,7 +17,6 @@ fn cmd_init{ } shift } - ls >[1=2] git/init $opts $args } diff --git a/sys/src/cmd/git/hist b/sys/src/cmd/git/hist index 7602d30f1..38ae279c4 100755 --- a/sys/src/cmd/git/hist +++ b/sys/src/cmd/git/hist @@ -7,8 +7,8 @@ gitup fn dodiff { while(t=`{read}){ h=$t(1) - o=$gitroot^.git/fs/object/`{git/query $h~} - c=$gitroot^.git/fs/object/$h + o=$gitfs/object/`{git/query $h~} + c=$gitfs/object/$h echo 'Hash:' $h echo -n 'Date: '; date `{walk -em $c/msg} echo -n 'Author: '; cat $c/author diff --git a/sys/src/cmd/git/import b/sys/src/cmd/git/import index 643e6865c..ebb5dbcb6 100755..100644 --- a/sys/src/cmd/git/import +++ b/sys/src/cmd/git/import @@ -96,8 +96,10 @@ fn apply @{ } git/walk -fRMA $files if(~ $#nocommit 0){ - if(hash=`{git/save -n $aname -e $amail -N $name -E $email -m $msg -d $date $parents $files}) + if(hash=`{git/save -n $aname -e $amail -N $name -E $email -m $msg -d $date $parents $files}){ echo $hash > $refpath + rm -f .git/index9/removed/$files + } } status='''' ' diff --git a/sys/src/cmd/ip/acmed.c b/sys/src/cmd/ip/acmed.c deleted file mode 100644 index c97429b3a..000000000 --- a/sys/src/cmd/ip/acmed.c +++ /dev/null @@ -1,905 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <json.h> -#include <mp.h> -#include <libsec.h> -#include <auth.h> -#include <authsrv.h> - -typedef struct Hdr Hdr; - -#pragma varargck type "E" char* - -struct Hdr { - char *name; - char *val; - int nval; -}; - -#define Keyspec "proto=rsa service=acme role=sign hash=sha256 acct=%s" -#define Useragent "useragent aclient-plan9" -#define Contenttype "contenttype application/jose+json" -#define between(x,min,max) (((min-1-x) & (x-max-1))>>8) -int debug; -int (*challengefn)(char*, char*, char*, int*); -char *keyspec; -char *provider = "https://acme-v02.api.letsencrypt.org/directory"; /* default endpoint */ -char *challengecmd; -char *challengeout; -char *keyid; -char *epnewnonce; -char *epnewacct; -char *epneworder; -char *eprevokecert; -char *epkeychange; -char *jwsthumb; -JSON *jwskey; - -#define dprint(...) if(debug)fprint(2, __VA_ARGS__); - -char* -evsmprint(char *fmt, va_list ap) -{ - char *r; - - if((r = vsmprint(fmt, ap)) == nil) - abort(); - return r; -} - -char* -esmprint(char *fmt, ...) -{ - va_list ap; - char *r; - - va_start(ap, fmt); - r = evsmprint(fmt, ap); - va_end(ap); - return r; -} - -int -encurl64chr(int o) -{ - int c; - - c = between(o, 0, 25) & ('A'+o); - c |= between(o, 26, 51) & ('a'+(o-26)); - c |= between(o, 52, 61) & ('0'+(o-52)); - c |= between(o, 62, 62) & ('-'); - c |= between(o, 63, 63) & ('_'); - return c; -} -char* -encurl64(void *in, int n) -{ - int lim; - char *out, *p; - - lim = 4*n/3 + 5; - if((out = malloc(lim)) == nil) - abort(); - enc64x(out, lim, in, n, encurl64chr); - if((p = strchr(out, '=')) != nil) - *p = 0; - return out; -} - -char* -signRS256(char *hdr, char *prot) -{ - uchar hash[SHA2_256dlen]; - DigestState *s; - AuthRpc *rpc; - int afd; - char *r; - - if((afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC)) < 0) - return nil; - if((rpc = auth_allocrpc(afd)) == nil){ - close(afd); - return nil; - } - if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){ - auth_freerpc(rpc); - close(afd); - return nil; - } - - s = sha2_256((uchar*)hdr, strlen(hdr), nil, nil); - s = sha2_256((uchar*)".", strlen("."), nil, s); - sha2_256((uchar*)prot, strlen(prot), hash, s); - - if(auth_rpc(rpc, "write", hash, sizeof(hash)) != ARok) - sysfatal("sign: write hash: %r"); - if(auth_rpc(rpc, "read", nil, 0) != ARok) - sysfatal("sign: read sig: %r"); - r = encurl64(rpc->arg, rpc->narg); - auth_freerpc(rpc); - close(afd); - return r; -} - -/* - * Reads all available data from an fd. - * guarantees returned value is terminated. - */ -static void* -slurp(int fd, int *n) -{ - char *b; - int r, sz; - - *n = 0; - sz = 32; - if((b = malloc(sz)) == nil) - abort(); - while(1){ - if(*n + 1 == sz){ - sz *= 2; - if((b = realloc(b, sz)) == nil) - abort(); - } - r = read(fd, b + *n, sz - *n - 1); - if(r == 0) - break; - if(r == -1){ - free(b); - return nil; - } - *n += r; - } - b[*n] = 0; - return b; -} - -static int -webopen(char *url, char *dir, int ndir) -{ - char buf[16]; - int n, cfd, conn; - - if((cfd = open("/mnt/web/clone", ORDWR|OCEXEC)) == -1) - return -1; - if((n = read(cfd, buf, sizeof(buf)-1)) == -1) - goto Error; - buf[n] = 0; - conn = atoi(buf); - - if(fprint(cfd, "url %s", url) == -1) - goto Error; - snprint(dir, ndir, "/mnt/web/%d", conn); - return cfd; -Error: - close(cfd); - return -1; -} - -static char* -get(char *url, int *n) -{ - char *r, dir[64], path[80]; - int cfd, dfd; - - r = nil; - dfd = -1; - if((cfd = webopen(url, dir, sizeof(dir))) == -1) - goto Error; - snprint(path, sizeof(path), "%s/%s", dir, "body"); - if((dfd = open(path, OREAD|OCEXEC)) == -1) - goto Error; - r = slurp(dfd, n); -Error: - if(dfd != -1) close(dfd); - if(cfd != -1) close(cfd); - return r; -} - -static char* -post(char *url, char *buf, int nbuf, int *nret, Hdr *h) -{ - char *r, dir[64], path[80]; - int cfd, dfd, hfd, ok; - - r = nil; - ok = 0; - dfd = -1; - hfd = -1; - if((cfd = webopen(url, dir, sizeof(dir))) == -1) - goto Error; - if(write(cfd, Contenttype, strlen(Contenttype)) == -1) - goto Error; - snprint(path, sizeof(path), "%s/%s", dir, "postbody"); - if((dfd = open(path, OWRITE|OCEXEC)) == -1) - goto Error; - if(write(dfd, buf, nbuf) != nbuf) - goto Error; - close(dfd); - snprint(path, sizeof(path), "%s/%s", dir, "body"); - if((dfd = open(path, OREAD|OCEXEC)) == -1) - goto Error; - if(h != nil){ - snprint(path, sizeof(path), "%s/%s", dir, h->name); - if((hfd = open(path, OREAD|OCEXEC)) == -1) - goto Error; - if((h->val = slurp(hfd, &h->nval)) == nil) - goto Error; - } - if((r = slurp(dfd, nret)) == nil) - goto Error; - ok = 1; -Error: - if(hfd != -1) close(hfd); - if(dfd != -1) close(dfd); - if(cfd != -1) close(cfd); - if(!ok && h != nil){ - free(h->val); - h->val = nil; - h->nval = 0; - } - return r; -} - -static int -endpoints(void) -{ - JSON *j; - JSONEl *e; - char *s; - int n; - - if((s = get(provider, &n)) == nil) - sysfatal("get %s: %r", provider); - if((j = jsonparse(s)) == nil) - sysfatal("parse endpoints: %r"); - if(j->t != JSONObject) - sysfatal("expected object"); - for(e = j->first; e != nil; e = e->next){ - if(e->val->t != JSONString) - continue; - if(strcmp(e->name, "keyChange") == 0) - epkeychange = strdup(e->val->s); - else if(strcmp(e->name, "newAccount") == 0) - epnewacct = strdup(e->val->s); - else if(strcmp(e->name, "newNonce") == 0) - epnewnonce = strdup(e->val->s); - else if(strcmp(e->name, "newOrder") == 0) - epneworder = strdup(e->val->s); - else if(strcmp(e->name, "revokeCert") == 0) - eprevokecert = strdup(e->val->s); - } - jsonfree(j); - free(s); - if(epnewnonce==nil|| epnewacct==nil || epneworder==nil - || eprevokecert==nil || epkeychange==nil){ - sysfatal("missing directory entries"); - return -1; - } - return 0; -} - -static char* -getnonce(void) -{ - char *r, dir[64], path[80]; - int n, cfd, dfd, hfd; - - r = nil; - dfd = -1; - hfd = -1; - if((cfd = webopen(epnewnonce, dir, sizeof(dir))) == -1) - goto Error; - fprint(cfd, "request HEAD"); - - snprint(path, sizeof(path), "%s/%s", dir, "body"); - if((dfd = open(path, OREAD|OCEXEC)) == -1) - goto Error; - snprint(path, sizeof(path), "%s/%s", dir, "replaynonce"); - if((hfd = open(path, OREAD|OCEXEC)) == -1) - goto Error; - r = slurp(hfd, &n); -Error: - if(hfd != -1) - close(hfd); - if(dfd != -1) - close(dfd); - close(cfd); - return r; -} - -char* -jwsenc(char *hdr, char *msg, int *nbuf) -{ - char *h, *m, *s, *r; - - h = encurl64(hdr, strlen(hdr)); - m = encurl64(msg, strlen(msg)); - s = signRS256(h, m); - if(s == nil) - return nil; - - r = esmprint( - "{\n" - "\"protected\": \"%s\",\n" - "\"payload\": \"%s\",\n" - "\"signature\": \"%s\"\n" - "}\n", - h, m, s); - *nbuf = strlen(r); - free(h); - free(m); - free(s); - - return r; -} - -char* -jwsheader(char *url) -{ - char *nonce; - - if((nonce = getnonce()) == nil) - sysfatal("get nonce: %r"); - return esmprint( - "{" - "\"alg\": \"RS256\"," - "\"nonce\": \"%E\"," - "\"kid\": \"%E\"," - "\"url\": \"%E\"" - "}", - nonce, keyid, url); -} - -char* -jwsrequest(char *url, int *nresp, Hdr *h, char *fmt, ...) -{ - char *hdr, *msg, *req, *resp; - int nreq; - va_list ap; - - va_start(ap, fmt); - hdr = jwsheader(url); - msg = evsmprint(fmt, ap); - req = jwsenc(hdr, msg, &nreq); - dprint("req=\"%s\"\n", req); - resp = post(url, req, nreq, nresp, h); - free(hdr); - free(req); - free(msg); - va_end(ap); - dprint("resp=%s\n", resp); - return resp; -} - -static void -mkaccount(char *addr) -{ - char *nonce, *hdr, *msg, *req, *resp; - int nreq, nresp; - Hdr loc = { "location" }; - - if((nonce = getnonce()) == nil) - sysfatal("get nonce: %r"); - hdr = esmprint( - "{" - "\"alg\": \"RS256\"," - "\"jwk\": %J," - "\"nonce\": \"%E\"," - "\"url\": \"%E\"" - "}", - jwskey, nonce, epnewacct); - msg = esmprint( - "{" - "\"termsOfServiceAgreed\": true," - "\"contact\": [\"mailto:%E\"]" - "}", - addr); - free(nonce); - if((req = jwsenc(hdr, msg, &nreq)) == nil) - sysfatal("failed to sign: %r"); - dprint("req=\"%s\"\n", req); - - if((resp = post(epnewacct, req, nreq, &nresp, &loc)) == nil) - sysfatal("failed req: %r"); - dprint("resp=%s, loc=%s\n", resp, loc.val); - keyid = loc.val; -} - -static JSON* -submitorder(char **dom, int ndom, Hdr *hdr) -{ - char *req, *resp, *sep, rbuf[8192]; - int nresp, i; - JSON *r; - - sep = ""; - req = seprint(rbuf, rbuf+sizeof(rbuf), - "{" - " \"identifiers\": ["); - for(i = 0; i < ndom; i++){ - req = seprint(req, rbuf+sizeof(rbuf), - "%s{" - " \"type\": \"dns\"," - " \"value\": \"%E\"" - "}", - sep, dom[i]); - sep = ","; - } - req = seprint(req, rbuf+sizeof(rbuf), - " ]," - " \"wildcard\": false" - "}"); - if(req - rbuf < 2) - sysfatal("truncated order"); - resp = jwsrequest(epneworder, &nresp, hdr, "%s", rbuf); - if(resp == nil) - sysfatal("submit order: %r"); - if((r = jsonparse(resp)) == nil) - sysfatal("parse order: %r"); - free(resp); - return r; -} - -static void -hashauthbuf(char *buf, int nbuf) -{ - uchar hash[SHA2_256dlen]; - char *enc; - - sha2_256((uchar*)buf, strlen(buf), hash, nil); - if((enc = encurl64(hash, sizeof(hash))) == nil) - sysfatal("hashbuf: %r"); - if(snprint(buf, nbuf, "%s", enc) != strlen(enc)) - sysfatal("hashbuf: buffer too small, truncated"); - free(enc); -} - -static int -runchallenge(char *ty, char *dom, char *tok, int *matched) -{ - char auth[1024]; - Waitmsg *w; - int pid; - - snprint(auth, sizeof(auth), "%s.%s", tok, jwsthumb); - if(strcmp(ty, "dns-01") == 0) - hashauthbuf(auth, sizeof(auth)); - - pid = fork(); - switch(pid){ - case -1: - return -1; - case 0: - dup(1, 2); - execl(challengecmd, challengecmd, ty, dom, tok, auth, nil); - sysfatal("%s: %r", challengecmd); - } - - while((w = wait()) != nil){ - if(w->pid != pid){ - free(w); - continue; - } - if(w->msg[0] == '\0'){ - free(w); - *matched = 1; - return 0; - } - werrstr("%s", w->msg); - free(w); - return -1; - } - return -1; -} - -static int -httpchallenge(char *ty, char *, char *tok, int *matched) -{ - char path[1024]; - int fd, r; - - if(strcmp(ty, "http-01") != 0) - return -1; - *matched = 1; - - snprint(path, sizeof(path), "%s/%s", challengeout, tok); - if((fd = create(path, OWRITE|OCEXEC, 0666)) == -1) - return -1; - r = fprint(fd, "%s.%s\n", tok, jwsthumb); - close(fd); - return r; -} - -static int -dnschallenge(char *ty, char *dom, char *tok, int *matched) -{ - char auth[1024]; - int fd; - - if(strcmp(ty, "dns-01") != 0) - return -1; - *matched = 1; - - snprint(auth, sizeof(auth), "%s.%s", tok, jwsthumb); - hashauthbuf(auth, sizeof(auth)); - - if((fd = create(challengeout, OWRITE|OCEXEC, 0666)) == -1){ - werrstr("could not create challenge: %r"); - return -1; - } - if(fprint(fd,"dom=_acme-challenge.%s soa=\n\ttxt=\"%s\"\n", dom, auth) == -1){ - werrstr("could not write challenge: %r"); - close(fd); - return -1; - } - close(fd); - - if((fd = open("/net/dns", OWRITE|OCEXEC)) == -1){ - werrstr("could not open dns ctl: %r"); - return -1; - } - if(fprint(fd, "refresh") == -1){ - werrstr("could not write dns refresh: %r"); - close(fd); - return -1; - } - close(fd); - - return 0; -} - -static int -challenge(JSON *j, char *authurl, JSON *id, char *dom[], int ndom, int *matched) -{ - JSON *dn, *ty, *url, *tok, *poll, *state; - char *resp; - int i, nresp; - - if((dn = jsonbyname(id, "value")) == nil) - return -1; - if(dn->t != JSONString) - return -1; - - /* make sure the identifier matches the csr */ - for(i = 0; i < ndom; i++){ - if(cistrcmp(dom[i], dn->s) == 0) - break; - } - if(i >= ndom){ - werrstr("unknown challenge identifier '%s'", dn->s); - return -1; - } - - if((ty = jsonbyname(j, "type")) == nil) - return -1; - if((url = jsonbyname(j, "url")) == nil) - return -1; - if((tok = jsonbyname(j, "token")) == nil) - return -1; - - if(ty->t != JSONString || url->t != JSONString || tok->t != JSONString) - return -1; - - dprint("trying challenge %s\n", ty->s); - if(challengefn(ty->s, dn->s, tok->s, matched) == -1){ - dprint("challengefn failed: %r\n"); - return -1; - } - - if((resp = jwsrequest(url->s, &nresp, nil, "{}")) == nil) - sysfatal("challenge: post %s: %r", url->s); - free(resp); - - for(i = 0; i < 60; i++){ - sleep(1000); - if((resp = jwsrequest(authurl, &nresp, nil, "")) == nil) - sysfatal("challenge: post %s: %r", url->s); - if((poll = jsonparse(resp)) == nil){ - free(resp); - return -1; - } - if((state = jsonbyname(poll, "status")) != nil && state->t == JSONString){ - if(strcmp(state->s, "valid") == 0){ - jsonfree(poll); - return 0; - } - else if(strcmp(state->s, "pending") != 0){ - fprint(2, "error: %J", poll); - werrstr("status '%s'", state->s); - jsonfree(poll); - return -1; - } - } - jsonfree(poll); - } - werrstr("timeout"); - return -1; -} - -static int -dochallenges(char *dom[], int ndom, JSON *order) -{ - JSON *chals, *j, *cl, *id; - JSONEl *ae, *ce; - int nresp, matched; - char *resp; - - if((j = jsonbyname(order, "authorizations")) == nil){ - werrstr("parse response: missing authorizations"); - return -1; - } - if(j->t != JSONArray){ - werrstr("parse response: authorizations must be array"); - return -1; - } - for(ae = j->first; ae != nil; ae = ae->next){ - if(ae->val->t != JSONString){ - werrstr("challenge: auth must be url"); - return -1; - } - if((resp = jwsrequest(ae->val->s, &nresp, nil, "")) == nil){ - werrstr("challenge: request %s: %r", ae->val->s); - return -1; - } - if((chals = jsonparse(resp)) == nil){ - werrstr("invalid challenge: %r"); - return -1; - } - if((id = jsonbyname(chals, "identifier")) == nil){ - werrstr("missing identifier"); - jsonfree(chals); - return -1; - } - if((cl = jsonbyname(chals, "challenges")) == nil){ - werrstr("missing challenge"); - jsonfree(chals); - return -1; - } - matched = 0; - for(ce = cl->first; ce != nil; ce = ce->next){ - if(challenge(ce->val, ae->val->s, id, dom, ndom, &matched) == 0) - break; - if(matched) - werrstr("could not complete challenge: %r"); - } - if(!matched) - sysfatal("no matching auth type"); - jsonfree(chals); - free(resp); - } - return 0; -} - -static int -submitcsr(JSON *order, char *b64csr) -{ - char *resp; - int nresp; - JSON *j; - - if((j = jsonbyname(order, "finalize")) == nil) - sysfatal("parse response: missing authorizations"); - if(j->t != JSONString) - werrstr("parse response: finalizer must be string"); - if((resp = jwsrequest(j->s, &nresp, nil, "{\"csr\":\"%E\"}", b64csr)) == nil) - sysfatal("submit csr: %r"); - free(resp); - return 0; -} - -static int -fetchcert(char *url) -{ - JSON *cert, *poll, *state; - int i, r, nresp; - char *resp; - - poll = nil; - for(i = 0; i < 60; i++){ - sleep(1000); - if((resp = jwsrequest(url, &nresp, nil, "")) == nil) - return -1; - if((poll = jsonparse(resp)) == nil){ - free(resp); - return -1; - } - free(resp); - if((state = jsonbyname(poll, "status")) != nil && state->t == JSONString){ - if(strcmp(state->s, "valid") == 0) - break; - else if(strcmp(state->s, "pending") != 0 && strcmp(state->s, "processing") != 0){ - fprint(2, "error: %J", poll); - werrstr("invalid request: %s", state->s); - jsonfree(poll); - return -1; - - } - } - jsonfree(poll); - } - if(poll == nil){ - werrstr("timed out"); - return -1; - } - if((cert = jsonbyname(poll, "certificate")) == nil || cert->t != JSONString){ - werrstr("missing cert url in response"); - jsonfree(poll); - return -1; - } - if((resp = jwsrequest(cert->s, &nresp, nil, "")) == nil){ - jsonfree(poll); - return -1; - } - jsonfree(poll); - r = write(1, resp, nresp); - free(resp); - if(r != nresp) - return -1; - return 0; -} - -static void -getcert(char *csrpath) -{ - char *csr, *dom[64], name[2048]; - uchar *der; - int nder, ndom, fd; - RSApub *rsa; - Hdr loc = { "location" }; - JSON *o; - - if((fd = open(csrpath, OREAD|OCEXEC)) == -1) - sysfatal("open %s: %r", csrpath); - if((der = slurp(fd, &nder)) == nil) - sysfatal("read %s: %r", csrpath); - if((rsa = X509reqtoRSApub(der, nder, name, sizeof(name))) == nil) - sysfatal("decode csr: %r"); - if((csr = encurl64(der, nder)) == nil) - sysfatal("encode %s: %r", csrpath); - if((ndom = getfields(name, dom, nelem(dom), 1, ", ")) == nelem(dom)) - sysfatal("too man domains"); - rsapubfree(rsa); - close(fd); - free(der); - - if((o = submitorder(dom, ndom, &loc)) == nil) - sysfatal("order: %r"); - if(dochallenges(dom, ndom, o) == -1) - sysfatal("challenge: %r"); - if(submitcsr(o, csr) == -1) - sysfatal("signing cert: %r"); - if(fetchcert(loc.val) == -1) - sysfatal("saving cert: %r"); - free(csr); -} - -static int -Econv(Fmt *f) -{ - char *s; - Rune r; - int w; - - w = 0; - s = va_arg(f->args, char*); - while(*s){ - s += chartorune(&r, s); - if(r == '\\' || r == '\"') - w += fmtrune(f, '\\'); - w += fmtrune(f, r); - } - return w; -} - -static int -loadkey(char *path) -{ - uchar h[SHA2_256dlen]; - char key[8192]; - JSON *j, *e, *kty, *n; - DigestState *ds; - int fd, nr; - - if((fd = open(path, OREAD|OCEXEC)) == -1) - return -1; - nr = readn(fd, key, sizeof(key)); - close(fd); - if(nr == -1) - return -1; - key[nr] = 0; - - if((j = jsonparse(key)) == nil) - return -1; - if((e = jsonbyname(j, "e")) == nil || e->t != JSONString) - return -1; - if((kty = jsonbyname(j, "kty")) == nil || kty->t != JSONString) - return -1; - if((n = jsonbyname(j, "n")) == nil || n->t != JSONString) - return -1; - - ds = sha2_256((uchar*)"{\"e\":\"", 6, nil, nil); - ds = sha2_256((uchar*)e->s, strlen(e->s), nil, ds); - ds = sha2_256((uchar*)"\",\"kty\":\"", 9, nil, ds); - ds = sha2_256((uchar*)kty->s, strlen(kty->s), nil, ds); - ds = sha2_256((uchar*)"\",\"n\":\"", 7, nil, ds); - ds = sha2_256((uchar*)n->s, strlen(n->s), nil, ds); - sha2_256((uchar*)"\"}", 2, h, ds); - jwskey = j; - jwsthumb = encurl64(h, sizeof(h)); - return 0; -} - -static void -usage(void) -{ - fprint(2, "usage: %s [-a acctkey] [-e cmd | -o chalout -t type] [-p provider] acct csr\n", argv0); - exits("usage"); -} - -void -main(int argc, char **argv) -{ - char *acctkey, *ct, *co; - - JSONfmtinstall(); - fmtinstall('E', Econv); - - ct = nil; - co = nil; - acctkey = nil; - ARGBEGIN{ - case 'd': - debug++; - break; - case 'a': - acctkey = EARGF(usage()); - break; - case 'e': - challengecmd = EARGF(usage()); - break; - case 'o': - co = EARGF(usage()); - break; - case 't': - ct = EARGF(usage()); - break; - case 'p': - provider = EARGF(usage()); - break; - default: - usage(); - break; - }ARGEND; - - if(challengecmd != nil){ - if(ct != nil || co != nil) - usage(); - challengeout = "/dev/null"; - challengefn = runchallenge; - }else if(ct == nil || strcmp(ct, "http") == 0){ - challengeout = (co != nil) ? co : "/usr/web/.well-known/acme-challenge"; - challengefn = httpchallenge; - }else if(strcmp(ct, "dns") == 0){ - challengeout = (co != nil) ? co : "/lib/ndb/dnschallenge"; - challengefn = dnschallenge; - }else { - sysfatal("unknown challenge type '%s'", ct); - } - - if(argc != 2) - usage(); - - if(acctkey == nil) - acctkey = esmprint("/sys/lib/tls/acmed/%s.pub", argv[0]); - if((keyspec = smprint(Keyspec, argv[0])) == nil) - sysfatal("smprint: %r"); - if(loadkey(acctkey) == -1) - sysfatal("load key: %r"); - - if(endpoints() == -1) - sysfatal("endpoints: %r"); - mkaccount(argv[0]); - getcert(argv[1]); - exits(nil); -} diff --git a/sys/src/cmd/ktrans/main.c b/sys/src/cmd/ktrans/main.c index 6c702c1e6..dbcd6dd17 100644 --- a/sys/src/cmd/ktrans/main.c +++ b/sys/src/cmd/ktrans/main.c @@ -2,6 +2,7 @@ #include <libc.h> #include <ctype.h> #include <bio.h> +#include <plumb.h> #include <thread.h> #include "hash.h" @@ -275,32 +276,28 @@ maplkup(int lang, char *s, Map *m) return hmapget(*h, s, m); } -typedef struct Msg Msg; -struct Msg { - char code; - char buf[64]; -}; -static Channel *dictch; -static Channel *output; -static Channel *input; -static char backspace[64]; +enum { Msgsize = 64 }; +static Channel *dictch; +static Channel *output; +static Channel *input; +static char backspace[Msgsize]; static int emitutf(Channel *out, char *u, int nrune) { - Msg m; + char b[Msgsize]; char *e; - m.code = 'c'; - e = pushutf(m.buf, m.buf + sizeof m.buf, u, nrune); - send(out, &m); - return e - m.buf; + b[0] = 'c'; + e = pushutf(b+1, b + Msgsize - 1, u, nrune); + send(out, b); + return e - b; } static void dictthread(void*) { - Msg m; + char m[Msgsize]; Rune r; int n; char *p; @@ -325,8 +322,8 @@ dictthread(void*) resetstr(&last, &line, &okuri, nil); threadsetname("dict"); - while(recv(dictch, &m) != -1){ - for(p = m.buf; *p; p += n){ + while(recv(dictch, m) != -1){ + for(p = m+1; *p; p += n){ n = chartorune(&r, p); if(r != ''){ if(selected >= 0){ @@ -441,7 +438,7 @@ dictthread(void*) } } -int +static int telexlkup(Str *line, Str *out) { Map lkup; @@ -454,7 +451,6 @@ telexlkup(Str *line, Str *out) if(hmapget(telex, buf, &lkup) < 0) return -1; - assert(lkup.leadstomore == 1); if(utflen(line->b) < 2) return 2; @@ -480,34 +476,32 @@ static void keythread(void*) { int lang; - Msg m; + char m[Msgsize]; Map lkup; char *p; int n, ln, rn; Rune r; char peek[UTFmax+1]; Str line, tbuf; - int mode; - mode = 0; peek[0] = lang = deflang; resetstr(&line, nil); if(lang == LangJP || lang == LangZH) emitutf(dictch, peek, 1); threadsetname("keytrans"); - while(recv(input, &m) != -1){ - if(m.code == 'z'){ + while(recv(input, m) != -1){ + if(m[0] == 'z'){ emitutf(dictch, "", 1); resetstr(&line, nil); continue; } - if(m.code != 'c'){ - send(output, &m); + if(m[0] != 'c'){ + send(output, m); continue; } - for(p = m.buf; *p; p += n){ + for(p = m+1; *p; p += n){ n = chartorune(&r, p); if(checklang(&lang, r)){ emitutf(dictch, "", 1); @@ -527,12 +521,8 @@ keythread(void*) resetstr(&line, nil); continue; } - if(lang == LangJP && isupper(*p)){ + if(lang == LangJP && isupper(*p)) *p = tolower(*p); - mode++; - } else { - mode = 0; - } } emitutf(output, p, 1); @@ -590,62 +580,95 @@ keythread(void*) static int kbdin; static int kbdout; -void +static void kbdtap(void*) { - Msg msg; + char m[Msgsize]; char buf[128]; char *p, *e; int n; threadsetname("kbdtap"); for(;;){ -Drop: + Drop: n = read(kbdin, buf, sizeof buf); if(n < 0) break; for(p = buf; p < buf+n;){ - msg.code = p[0]; - p++; - switch(msg.code){ + switch(*p){ case 'c': case 'k': case 'K': case 'z': break; default: goto Drop; } - e = utfecpy(msg.buf, msg.buf + sizeof msg.buf, p); - p += e - msg.buf; + *m = *p++; + e = utfecpy(m+1, m + Msgsize - 1, p); + p += e - m; p++; - if(send(input, &msg) == -1) + if(send(input, m) == -1) return; } } } -void +static void kbdsink(void*) { - Msg m; + char in[Msgsize]; + char out[Msgsize]; char *p; + int n; Rune rn; + out[0] = 'c'; threadsetname("kbdsink"); - while(recv(output, &m) != -1){ - if(m.code != 'c'){ - fprint(kbdout, "%c%s", m.code, m.buf); + while(recv(output, in) != -1){ + if(in[0] != 'c'){ + if(write(kbdout, in, strlen(in)+1) < 0) + break; continue; } - p = m.buf; - for(;;){ - p += chartorune(&rn, p); + + for(p = in+1; *p; p += n){ + n = chartorune(&rn, p); if(rn == Runeerror || rn == '\0') break; - fprint(kbdout, "c%C", rn); + memmove(out+1, p, n); + out[1+n] = '\0'; + if(write(kbdout, out, 1+n+1) < 0) + break; } } } +static int plumbfd; + +static void +plumbproc(void*) +{ + char m[Msgsize]; + Plumbmsg *p; + + threadsetname("plumbproc"); + for(; p = plumbrecv(plumbfd); plumbfree(p)){ + if(p->ndata > sizeof m - 1) + continue; + memmove(m, p->data, p->ndata); + m[p->ndata] = '\0'; + + m[1] = parselang(m); + if(m[1] == -1) + continue; + m[0] = 'c'; + m[2] = '\0'; + + if(send(input, m) == -1) + break; + } + plumbfree(p); +} + void usage(void) { @@ -704,9 +727,13 @@ threadmain(int argc, char *argv[]) hangul = openmap("/lib/ktrans/hangul.map"); telex = openmap("/lib/ktrans/telex.map"); - dictch = chancreate(sizeof(Msg), 0); - input = chancreate(sizeof(Msg), 0); - output = chancreate(sizeof(Msg), 0); + dictch = chancreate(Msgsize, 0); + input = chancreate(Msgsize, 0); + output = chancreate(Msgsize, 0); + + plumbfd = plumbopen("lang", OREAD); + if(plumbfd >= 0) + proccreate(plumbproc, nil, mainstacksize); proccreate(kbdtap, nil, mainstacksize); proccreate(kbdsink, nil, mainstacksize); diff --git a/sys/src/cmd/nusb/disk/disk.c b/sys/src/cmd/nusb/disk/disk.c index 196894cfe..2fb8fc324 100644 --- a/sys/src/cmd/nusb/disk/disk.c +++ b/sys/src/cmd/nusb/disk/disk.c @@ -155,10 +155,10 @@ ctlstring(Umsc *lun) part = &lun->part[0]; fmtstrinit(&fmt); - fmtprint(&fmt, "dev %s\n", dev->dir); - fmtprint(&fmt, "lun %zd\n", lun - &ums->lun[0]); if(lun->flags & Finqok) fmtprint(&fmt, "inquiry %s\n", lun->inq); + fmtprint(&fmt, "dev %s\n", dev->dir); + fmtprint(&fmt, "lun %zd\n", lun - &ums->lun[0]); if(lun->blocks > 0) fmtprint(&fmt, "geometry %llud %ld\n", lun->blocks, lun->lbsize); for (p = &part[Qdata+1]; p < &part[Qmax]; p++) diff --git a/sys/src/cmd/nusb/kb/hid.h b/sys/src/cmd/nusb/kb/hid.h index 10e614f4b..5c51250aa 100644 --- a/sys/src/cmd/nusb/kb/hid.h +++ b/sys/src/cmd/nusb/kb/hid.h @@ -4,6 +4,7 @@ enum { Stack = 32 * 1024, + Nkey = 64, /* HID class subclass protocol ids */ PtrCSP = 0x020103, /* mouse.boot.hid */ diff --git a/sys/src/cmd/nusb/kb/kb.c b/sys/src/cmd/nusb/kb/kb.c index e748c9268..5a7b8ee5e 100644 --- a/sys/src/cmd/nusb/kb/kb.c +++ b/sys/src/cmd/nusb/kb/kb.c @@ -13,21 +13,21 @@ #include <u.h> #include <libc.h> +#include <ctype.h> +#include <fcall.h> #include <thread.h> +#include <9p.h> #include "usb.h" #include "hid.h" enum { - Awakemsg=0xdeaddead, + Awakemsg = 0xdeaddead, Diemsg = 0xbeefbeef, + Rawon = 0x0defaced, }; -enum -{ - Kbdelay = 500, - Kbrepeat = 100, -}; +char user[] = "kb"; typedef struct Hiddev Hiddev; struct Hiddev @@ -78,7 +78,7 @@ struct Hidreport Hidslot s[16]; int nk; - uchar k[64]; + ushort k[Nkey]; int o; uchar *e; @@ -92,6 +92,7 @@ enum { /* Scan codes (see kbd.c) */ SCesc1 = 0xe0, /* first of a 2-character sequence */ SCesc2 = 0xe1, + Consumer = 0x100, /* the key is on consumer page */ Keyup = 0x80, /* flag bit */ Keymask = 0x7f, /* regular scan code bits */ }; @@ -101,12 +102,12 @@ enum { */ #define isext(sc) ((sc) >= 0x80) +static char sctab[2*256] = +{ /* * key code to scan code; for the page table used by * the logitech bluetooth keyboard. */ -static char sctab[256] = -{ [0x00] 0x0, 0x0, 0x0, 0x0, 0x1e, 0x30, 0x2e, 0x20, [0x08] 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, [0x10] 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, @@ -124,7 +125,7 @@ static char sctab[256] = [0x70] 0xf8, 0xf9, 0xfa, 0xfb, 0x0, 0x0, 0x0, 0x0, [0x78] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf1, [0x80] 0xf3, 0xf2, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, -[0x88] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x88] 0x70, 0x0, 0x79, 0x7b, 0x0, 0x0, 0x0, 0x0, [0x90] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0x98] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xa0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -135,10 +136,43 @@ static char sctab[256] = [0xc8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xd0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xd8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -[0xe0] 0x1d, 0x2a, 0x38, 0xdb, 0xe1, 0x36, 0xb8, 0xfe, +[0xe0] 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xfe, [0xe8] 0x0, 0x0, 0x0, 0x0, 0x0, 0xf3, 0xf2, 0xf1, [0xf0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xf8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +/* consumer page to scan code */ +[0x100] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x108] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x110] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x118] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x120] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x128] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x130] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x138] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x140] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x148] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x150] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x158] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x160] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x168] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9a, +[0x170] 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x178] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x180] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x188] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x190] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x198] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1a0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1a8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1b0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x99, 0x90, 0x0, +[0x1b8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1c0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1c8] 0x0, 0x0, 0x0, 0x0, 0x0, 0xa2, 0x0, 0x0, +[0x1d0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1d8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1e0] 0x0, 0x0, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1e8] 0x0, 0xb0, 0xae, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1f0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +[0x1f8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; static uchar kbdbootrep[] = { @@ -165,6 +199,9 @@ static uchar ptrbootrep[] = { }; static int debug = 0; +static int kbdelay = 500; +static int kbrepeat = 100; +static int havekbd; static int signext(int v, int bits) @@ -377,12 +414,6 @@ setproto(Hiddev *f, Iface *iface) return usbcmd(f->dev, Rh2d|Rclass|Riface, Setproto, proto, iface->id, nil, 0); } -static int -setleds(Hiddev* f, int, uchar leds) -{ - return usbcmd(f->dev, Rh2d|Rclass|Riface, Setreport, Reportout, 0, &leds, 1); -} - static void hdfree(Hiddev *f) { @@ -498,9 +529,9 @@ repeatproc(void* arg) continue; } sc = l & 0xff; - t = Kbdelay; + t = kbdelay; if(alt(a) == 1){ - t = Kbrepeat; + t = kbrepeat; while(alt(a) == 1) putscan(f, sc, 0); } @@ -528,7 +559,7 @@ hidparse(int t, int f, int g[], int l[], int, void *a) { Hidreport *p = a; Hidslot *s = &p->s[p->ns]; - int v, m; + int v, m, cp; switch(t){ case Input: @@ -571,11 +602,11 @@ hidparse(int t, int f, int g[], int l[], int, void *a) if(debug > 1) fprint(2, "hidparse: t=%x f=%x usage=%x v=%x\n", t, f, l[Usage], v); - if((l[Usage]>>16) == 0x07){ /* keycode */ + if((cp = ((l[Usage]>>16) == 0x0c)) || (l[Usage]>>16) == 0x07){ /* consumer/keycode */ if((f & (Fvar|Farray)) == Fvar) if(v != 0) v = l[Usage] & 0xFF; if(p->nk < nelem(p->k) && v != 0) - p->k[p->nk++] = v; + p->k[p->nk++] = v | cp*Consumer; return; } @@ -677,12 +708,23 @@ sethipri(void) close(fd); } +static ushort * +keykey(ushort *a, ushort k, int n) +{ + while(n > 0){ + if(*a++ == k) + return a-1; + n--; + } + return nil; +} + static void readerproc(void* a) { char err[ERRMAX], mbuf[80]; - uchar lastk[64], uk, dk; - int i, c, nerrs, bpress, lastb, nlastk; + ushort lastk[Nkey], uks[Nkey], dks[Nkey], nuks, ndks; + int i, c, nerrs, bpress, lastb, nlastk, stopped; int abs, x, y, z, b; Hidreport p; Hidslot lasts[nelem(p.s)], *s, *l; @@ -730,7 +772,7 @@ readerproc(void* a) if(debug){ fprint(2, "kbd: "); for(i = 0; i < p.nk; i++) - fprint(2, "%#2.2ux ", p.k[i]); + fprint(2, "%#4.4ux ", p.k[i]); fprint(2, "\n"); } @@ -745,25 +787,36 @@ readerproc(void* a) proccreate(repeatproc, f, Stack); } - dk = uk = 0; - for(i=0; i<nlastk; i++){ - if(memchr(p.k, lastk[i], p.nk) == nil){ - uk = sctab[lastk[i]]; - putscan(f, uk, Keyup); - } + /* collect key presses/releases */ + for(i=nuks=0; i<nlastk; i++){ + if(keykey(p.k, lastk[i], p.nk) == nil) + uks[nuks++] = sctab[lastk[i]]; } - for(i=0; i<p.nk; i++){ - if(memchr(lastk, p.k[i], nlastk) == nil){ - dk = sctab[p.k[i]]; - putscan(f, dk, 0); + for(i=ndks=0; i<p.nk; i++){ + if(keykey(lastk, p.k[i], nlastk) == nil) + dks[ndks++] = sctab[p.k[i]]; + } + + /* + * stop the repeats first to avoid race condition when + * the key is released but the repeat happens right after + */ + for(stopped = i = 0; i < nuks; i++){ + if(ndks == 0 || keykey(dks, uks[i], ndks) != nil){ + stoprepeat(f); + stopped = 1; + break; } } - if(uk != 0 && (dk == 0 || dk == uk)) - stoprepeat(f); - else if(dk != 0) - startrepeat(f, dk); + for(i = 0; i < nuks; i++) + putscan(f, uks[i], Keyup); + for(i = 0; i < ndks; i++) + putscan(f, dks[i], 0); + + if(stopped == 0 && ndks > 0) + startrepeat(f, dks[ndks-1]); - memmove(lastk, p.k, nlastk = p.nk); + memmove(lastk, p.k, (nlastk = p.nk)*sizeof(lastk[0])); p.nk = 0; } @@ -871,7 +924,7 @@ quirks(Hiddev *f) } } -static void +static int hdsetup(Dev *d, Ep *ep) { Hiddev *f; @@ -896,12 +949,71 @@ hdsetup(Dev *d, Ep *ep) } quirks(f); procrfork(readerproc, f, Stack, RFNOTEG); - return; + return 0; Err: hdfree(f); + return -1; +} + +static void +fsread(Req *r) +{ + char msg[48], *s, *e; + + s = msg; + e = msg+sizeof(msg); + *s = 0; + if(havekbd) + e = seprint(s, e, "repeat %d\ndelay %d\n", kbrepeat, kbdelay); + USED(e); + readstr(r, msg); + respond(r, nil); } static void +fswrite(Req *r) +{ + char msg[256], *f[4]; + void *data; + int nf, sz; + Dev *dev; + + dev = r->fid->file->aux; + data = r->ifcall.data; + sz = r->ifcall.count; + if(r->fid->aux == (void*)Rawon){ + if(sz == 6 && memcmp(data, "rawoff", 6) == 0) + r->fid->aux = nil; + else if(usbcmd(dev, Rh2d|Rclass|Riface, Setreport, Reportout, 0, data, sz) < 0){ + responderror(r); + return; + } + }else{ + snprint(msg, sizeof(msg), "%.*s", utfnlen(data, sz), data); + nf = tokenize(msg, f, nelem(f)); + if(nf == 1 && strcmp(f[0], "rawon") == 0) + r->fid->aux = (void*)Rawon; + else if(nf == 2 && strcmp(f[0], "repeat") == 0) + kbrepeat = atoi(f[1]); + else if(nf == 2 && strcmp(f[0], "delay") == 0) + kbdelay = atoi(f[1]); + else if(nf == 2 && strcmp(f[0], "debug") == 0) + debug = atoi(f[1]); + else{ + respond(r, "invalid ctl message"); + return; + } + } + r->ofcall.count = sz; + respond(r, nil); +} + +static Srv fs = { + .read = fsread, + .write = fswrite, +}; + +static void usage(void) { fprint(2, "usage: %s [-d] devid\n", argv0); @@ -911,10 +1023,11 @@ usage(void) void threadmain(int argc, char* argv[]) { - int i; + int i, n; Dev *d; Ep *ep; Usbdev *ud; + char buf[32]; ARGBEGIN{ case 'd': @@ -929,20 +1042,28 @@ threadmain(int argc, char* argv[]) if(d == nil) sysfatal("getdev: %r"); ud = d->usb; - for(i = 0; i < nelem(ud->ep); i++){ + for(i = n = 0; i < nelem(ud->ep); i++){ if((ep = ud->ep[i]) == nil) continue; if(ep->type != Eintr || ep->dir != Ein) continue; switch(ep->iface->csp){ case KbdCSP: + havekbd = 1; case PtrCSP: case PtrNonBootCSP: case HidCSP: - hdsetup(d, ep); + n += hdsetup(d, ep) == 0; break; } } closedev(d); + if(n > 0){ + fs.tree = alloctree(user, "usb", DMDIR|0555, nil); + snprint(buf, sizeof buf, "hidU%sctl", d->hname); + createfile(fs.tree->root, buf, user, 0666, d); + snprint(buf, sizeof buf, "%s.hid", d->hname); + threadpostsharesrv(&fs, nil, "usb", buf); + } threadexits(nil); } diff --git a/sys/src/cmd/patch.c b/sys/src/cmd/patch.c index 8e402bba8..5d882150b 100644 --- a/sys/src/cmd/patch.c +++ b/sys/src/cmd/patch.c @@ -393,12 +393,11 @@ blat(char *old, char *new, char *o, usize len) char *tmp; int fd; - if(strcmp(new, "/dev/null") == 0 && len != 0){ - sysfatal("diff modifies removed file"); - return; - } tmp = nil; - if(!dryrun){ + if(strcmp(new, "/dev/null") == 0){ + if(len != 0) + sysfatal("diff modifies removed file"); + }else if(!dryrun){ if(mkpath(new) == -1) sysfatal("mkpath %s: %r", new); if((tmp = smprint("%s.tmp%d", new, getpid())) == nil) @@ -428,7 +427,7 @@ finish(int ok) for(i = 0; i < nchanged; i++){ c = &changed[i]; if(!ok){ - if(remove(c->tmp) == -1) + if(c->tmp != nil && remove(c->tmp) == -1) fprint(2, "remove %s: %r\n", c->tmp); goto Free; } @@ -460,7 +459,7 @@ Free: free(changed); } -int +void slurp(Fbuf *f, char *path) { int n, i, fd, sz, len, nlines, linesz; @@ -503,7 +502,6 @@ slurp(Fbuf *f, char *path) f->lines = lines; f->nlines = nlines; f->lastln = -1; - return 0; } char* @@ -517,7 +515,7 @@ search(Fbuf *f, Hunk *h, char *fname) for(fuzz = 0; scanning && fuzz <= nfuzz; fuzz++){ scanning = 0; ln = h->oldln - fuzz; - if(ln > f->lastln){ + if(ln > f->lastln && ln < f->nlines){ off = f->lines[ln]; if(off + len > f->len) continue; @@ -527,8 +525,8 @@ search(Fbuf *f, Hunk *h, char *fname) return f->buf + off; } } - ln = h->oldln + fuzz - 1; - if(ln <= f->nlines){ + ln = h->oldln + fuzz + 1; + if(ln > f->lastln && ln < f->nlines){ off = f->lines[ln]; if(off + len >= f->len) continue; @@ -558,22 +556,35 @@ append(char *o, int *sz, char *s, char *e) int apply(Patch *p, char *fname) { - char *o, *s, *e, *curfile; + char *o, *s, *e, *curfile, *nextfile; int i, osz; - Hunk *h; + Hunk *h, *prevh; Fbuf f; e = nil; o = nil; osz = 0; curfile = nil; + h = nil; + prevh = nil; for(i = 0; i < p->nhunk; i++){ h = &p->hunk[i]; - if(curfile == nil || strcmp(curfile, h->newpath) != 0){ - if(!dryrun && slurp(&f, h->oldpath) == -1) - sysfatal("slurp %s: %r", h->oldpath); - curfile = h->newpath; - e = f.buf; + if(strcmp(h->newpath, "/dev/null") == 0) + nextfile = h->oldpath; + else + nextfile = h->newpath; + if(curfile == nil || strcmp(curfile, nextfile) != 0){ + if(curfile != nil){ + if(!dryrun) + o = append(o, &osz, e, f.buf + f.len); + blat(prevh->oldpath, prevh->newpath, o, osz); + osz = 0; + } + if(!dryrun){ + slurp(&f, h->oldpath); + e = f.buf; + } + curfile = nextfile; } if(!dryrun){ s = e; @@ -582,11 +593,12 @@ apply(Patch *p, char *fname) 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){ + prevh = h; + } + if(curfile != nil){ + if(!dryrun) o = append(o, &osz, e, f.buf + f.len); - blat(h->oldpath, h->newpath, o, osz); - osz = 0; - } + blat(h->oldpath, h->newpath, o, osz); } free(o); return 0; diff --git a/sys/src/cmd/reform/pm.c b/sys/src/cmd/reform/pm.c index 27de4ac83..c6f609430 100644 --- a/sys/src/cmd/reform/pm.c +++ b/sys/src/cmd/reform/pm.c @@ -3,11 +3,14 @@ #include <fcall.h> #include <thread.h> #include <9p.h> +#include <draw.h> +#include <memdraw.h> enum { Mhz = 1000*1000, Pwmsrcclk = 25*Mhz, + Kbdlightmax = 8, Scharge = 0, Sovervolted, @@ -22,8 +25,15 @@ enum Light = 1, Temp, Battery, + Kbdoled, Pmctl, + KbdoledW = 126, + KbdoledH = 32, + + Lcd = 0, + Kbd, + PWMSAR = 0x0c/4, PWMPR = 0x10/4, @@ -68,9 +78,13 @@ enum STAT_RR = 1<<3, }; +static char *uid = "pm"; static Reqqueue *lpcreq; static u32int *pwm2, *tmu, *spi2; -static char *uid = "pm"; +static int kbdlight = 0; +static int kbdhidfd = -1; +static Memimage *kbdoled; +static u8int kbdoledraw[4+KbdoledW*KbdoledH/8] = {'W', 'B', 'I', 'T', 0}; static void wr(u32int *base, int reg, u32int v) @@ -86,8 +100,96 @@ rd(u32int *base, int reg) return base != nil ? base[reg] : -1; } -static void -setlight(int p) +static char * +readall(int f) +{ + int bufsz, sz, n; + char *s; + + bufsz = 2047; + s = nil; + for(sz = 0;; sz += n){ + if(bufsz-sz < 2048){ + bufsz *= 2; + s = realloc(s, bufsz); + } + if((n = readn(f, s+sz, bufsz-sz-1)) < 1) + break; + } + if(n < 0 || sz < 1){ + if(n == 0) + werrstr("empty"); + free(s); + return nil; + } + s[sz] = 0; + + return s; +} + +static int +openkbdhid(void) +{ + char path[32], *s, *k, *e; + int f; + + if(kbdhidfd < 0 && (f = open("/dev/usb/ctl", OREAD)) >= 0){ + if((s = readall(f)) != nil && + (k = strstr(s, "MNT 'Reform Keyboard'")) != nil && + (e = strchr(k+22, ' ')) != nil){ + *e = 0; + snprint(path, sizeof(path), "/dev/hidU%sctl", k+22); + if((kbdhidfd = open(path, OWRITE)) >= 0 && write(kbdhidfd, "rawon", 5) != 5){ + close(kbdhidfd); + kbdhidfd = -1; + } + } + free(s); + close(f); + } + + return kbdhidfd < 0; +} + +static int +loadkbdoled(void *data, int size) +{ + int x, y, i, k, v, bpl; + u8int *p, q; + + if(openkbdhid() != 0) + return -1; + if(size == 0) + return write(kbdhidfd, "WCLR", 4); + + bpl = bytesperline(kbdoled->r, kbdoled->depth); + if(size == 60+bpl*KbdoledH){ + data = (u8int*)data + 60; + size -= 60; + }else if(size != bpl*KbdoledH){ + werrstr("invalid image: expected %dx%d GREY1 (%d bytes)", KbdoledW, KbdoledH, bpl*KbdoledH); + return -1; + } + + k = loadmemimage(kbdoled, kbdoled->r, data, size); + if(k < 0 || openkbdhid() != 0) + return -1; + for(y = 0, i = 4; y < KbdoledH; y += 8){ + for(x = v = 0; x < KbdoledW; x++, v = (v+1)&7){ + SET(p); + if(v == 0) + p = byteaddr(kbdoled, Pt(x,y)); + for(k = q = 0; k < 8; k++) + q |= ((p[bpl*k] >> (7-v)) & 1) << k; + kbdoledraw[i++] = q; + } + } + + return write(kbdhidfd, kbdoledraw, sizeof(kbdoledraw)); +} + +static int +setlight(int k, int p) { u32int v; @@ -96,17 +198,37 @@ setlight(int p) if(p > 100) p = 100; - v = Pwmsrcclk / rd(pwm2, PWMSAR); - wr(pwm2, PWMPR, (Pwmsrcclk/(v*p/100))-2); + if(k == Lcd){ + v = Pwmsrcclk / rd(pwm2, PWMSAR); + wr(pwm2, PWMPR, (Pwmsrcclk/(v*p/100))-2); + return 0; + }else if(k == Kbd && openkbdhid() == 0){ + v = Kbdlightmax*p/100; + if(fprint(kbdhidfd, "LITE%c", '0'+v) > 0){ + kbdlight = v; + return 0; + } + close(kbdhidfd); + kbdhidfd = -1; + kbdlight = 0; + } + + return -1; } static int -getlight(void) +getlight(int k) { u32int m, v; - m = Pwmsrcclk / rd(pwm2, PWMSAR); - v = Pwmsrcclk / (rd(pwm2, PWMPR)+2); + SET(m, v); + if(k == Lcd){ + m = Pwmsrcclk / rd(pwm2, PWMSAR); + v = Pwmsrcclk / (rd(pwm2, PWMPR)+2); + }else if(k == Kbd){ + m = Kbdlightmax; + v = kbdlight; + } return v*100/m; } @@ -194,16 +316,16 @@ lpccall(char cmd, u8int arg, void *ret) wr(spi2, SPIx_TXDATA, cmd); wr(spi2, SPIx_TXDATA, arg); wr(spi2, SPIx_CONREG, con | CON_XCH); - sleep(60); - - /* LPC buffers 3 bytes without responding, ignore (including garbage) */ - while(rd(spi2, SPIx_STATREG) & STAT_RR) - rd(spi2, SPIx_RXDATA); /* - * at this point LPC hopefully is blocked waiting for - * chip select to go active + * LPC buffers 3 bytes without responding, but spends some time + * to prepare the response. 50ms should be safe, add a bit more + * to be sure LPC is blocked waiting for the chip select to go + * active again. */ + sleep(60); + while(rd(spi2, SPIx_STATREG) & STAT_RR) + rd(spi2, SPIx_RXDATA); /* expecting 8 bytes, start the exchange */ for(i = 0; i < 8; i++) @@ -315,7 +437,7 @@ fsread(Req *r) if(r->ifcall.offset == 0){ aux = r->fid->file->aux; if(aux == (void*)Light){ - snprint(msg, sizeof(msg), "lcd %d\n", getlight()); + snprint(msg, sizeof(msg), "lcd %d\nkbd %d\n", getlight(Lcd), getlight(Kbd)); }else if(aux == (void*)Temp){ if((c = getcputemp()) < 0){ responderror(r); @@ -339,29 +461,55 @@ static void fswrite(Req *r) { char msg[256], *f[4]; - int nf, v, p; + int nf, v, p, k; void *aux; - snprint(msg, sizeof(msg), "%.*s", - utfnlen((char*)r->ifcall.data, r->ifcall.count), (char*)r->ifcall.data); - nf = tokenize(msg, f, nelem(f)); aux = r->fid->file->aux; + + if(aux == (void*)Kbdoled){ + if(loadkbdoled(r->ifcall.data, r->ifcall.count) < 0){ +Err: + responderror(r); + return; + } + r->ofcall.count = r->ifcall.count; + respond(r, nil); + return; + } + + snprint(msg, sizeof(msg), "%.*s", utfnlen(r->ifcall.data, r->ifcall.count), r->ifcall.data); + nf = tokenize(msg, f, nelem(f)); if(aux == (void*)Light){ if(nf < 2){ Bad: respond(r, "invalid ctl message"); return; } - if(strcmp(f[0], "lcd") == 0){ - v = atoi(f[1]); - if(*f[1] == '+' || *f[1] == '-') - v += getlight(); - setlight(v); - } + if(strcmp(f[0], "lcd") == 0) + k = Lcd; + else if(strcmp(f[0], "kbd") == 0) + k = Kbd; + else + goto Bad; + v = atoi(f[1]); + if(*f[1] == '+' || *f[1] == '-') + v += getlight(k); + if(setlight(k, v) != 0) + goto Err; }else if(aux == (void*)Pmctl){ p = -1; - if(nf == 2 && strcmp(f[0], "power") == 0 && strcmp(f[1], "off") == 0) - p = Psomoff; + if(nf >= 2 && strcmp(f[0], "power") == 0){ + if(nf == 2 && strcmp(f[1], "off") == 0){ + /* + * LPC firmware might not be up to date so try + * shutting down through the keyboard first + */ + if(openkbdhid() == 0){ + write(kbdhidfd, "PWR0", 4); + sleep(2000); /* give it a chance */ + } + } + } if(p < 0) goto Bad; lpccall('p', p, msg); @@ -425,11 +573,16 @@ threadmain(int argc, char **argv) if((spi2 = segattach(0, "ecspi2", 0, 0x20)) == (void*)-1) sysfatal("no spi2"); tmuinit(); + if(memimageinit() != 0) + sysfatal("%r"); + if((kbdoled = allocmemimage(Rect(0, 0, KbdoledW, KbdoledH), GREY1)) == nil) + sysfatal("%r"); lpcreq = reqqueuecreate(); fs.tree = alloctree(uid, uid, DMDIR|0555, nil); - createfile(fs.tree->root, "battery", uid, 0444,(void*)Battery); + createfile(fs.tree->root, "battery", uid, 0444, (void*)Battery); createfile(fs.tree->root, "cputemp", uid, 0444, (void*)Temp); createfile(fs.tree->root, "light", uid, 0666, (void*)Light); + createfile(fs.tree->root, "kbdoled", uid, 0222, (void*)Kbdoled); createfile(fs.tree->root, "pmctl", uid, 0666, (void*)Pmctl); threadpostmountsrv(&fs, srv, mtpt, MAFTER); diff --git a/sys/src/cmd/reform/shortcuts.c b/sys/src/cmd/reform/shortcuts.c index dc3fdc85f..ce8cbdc43 100644 --- a/sys/src/cmd/reform/shortcuts.c +++ b/sys/src/cmd/reform/shortcuts.c @@ -1,22 +1,32 @@ #include <u.h> #include <libc.h> #include <keyboard.h> +#include <plumb.h> static int lightstep = 5, volstep = 3; -static int light, vol, actl, mod; +static int light, vol, actl; + +static void +aplumb(char *s) +{ + int f; + + if((f = plumbopen("send", OWRITE)) >= 0){ + plumbsendtext(f, "shortcuts", "audio", "/", s); + close(f); + } +} static void process(char *s) { char b[128], *p; - int n, o; + int n, o, skip; Rune r; - if(*s == 'K' && s[1] == 0) - mod = 0; - o = 0; b[o++] = *s; + for(p = s+1; *p != 0; p += n){ if((n = chartorune(&r, p)) == 1 && r == Runeerror){ /* bail out */ @@ -27,31 +37,31 @@ process(char *s) break; } - if(*s == 'k' && r == Kmod4){ - mod = 1; - }else if(*s == 'K'){ - if(mod && r >= (KF|1) && r <= (KF|4)) - continue; - if(r == Kmod4) - mod = 0; - }else if(mod && ((r >= (KF|1) && r <= (KF|4) || r == Kesc))){ - if(*s == 'c'){ - if(r == (KF|1)) - fprint(light, "lcd %+d", -lightstep); - else if(r == (KF|2)) - fprint(light, "lcd %+d", lightstep); - else if(r == (KF|3)) - fprint(vol, "master %+d", -volstep); - else if(r == (KF|4)) - fprint(vol, "master %+d", volstep); - else if(r == Kesc) - fprint(actl, "master toggle"); - } - continue; + if(skip = (*s == 'c')){ + if(r == Kbrtdn) + fprint(light, "lcd %+d", -lightstep); + else if(r == Kbrtup) + fprint(light, "lcd %+d", lightstep); + else if(r == Kvoldn) + fprint(vol, "master %+d", -volstep); + else if(r == Kvolup) + fprint(vol, "master %+d", volstep); + else if(r == Kmute) + fprint(actl, "master toggle"); + else if(r == Ksbwd) + aplumb("key <"); + else if(r == Ksfwd) + aplumb("key >"); + else if(r == Kpause) + aplumb("key p"); + else + skip = 0; } - memmove(b+o, p, n); - o += n; + if(!skip){ + memmove(b+o, p, n); + o += n; + } } /* all runes filtered out - ignore completely */ diff --git a/sys/src/cmd/rio/rio.c b/sys/src/cmd/rio/rio.c index daefffe93..2e59a636d 100644 --- a/sys/src/cmd/rio/rio.c +++ b/sys/src/cmd/rio/rio.c @@ -393,32 +393,16 @@ keyboardtap(void*) threadsetname("keyboardtap"); enum { Awin, Actl, Afrom, Adev, Ato, Ainp, Awatch, NALT }; - static Alt alts[NALT+1]; - /* ctl */ - alts[Awin].c = wintap; - alts[Awin].v = &w; - alts[Awin].op = CHANRCV; - alts[Actl].c = ctltap; - alts[Actl].v = &ctl; - alts[Actl].op = CHANRCV; - /* kbd input */ - alts[Afrom].c = fromtap; - alts[Afrom].v = &s; - alts[Afrom].op = CHANRCV; - alts[Adev].c = kbdchan; - alts[Adev].v = &s; - alts[Adev].op = CHANRCV; - /* kbd output */ - alts[Ato].c = totap; - alts[Ato].v = &s; - alts[Ato].op = CHANNOP; - alts[Ainp].c = nil; - alts[Ainp].v = &s; - alts[Ainp].op = CHANNOP; - alts[Awatch].c = totap; - alts[Awatch].v = &watched; - alts[Awatch].op = CHANNOP; - alts[NALT].op = CHANEND; + Alt alts[NALT+1] = { + [Awin] {.c = wintap, .v = &w, .op = CHANRCV}, + [Actl] {.c = ctltap, .v = &ctl, .op = CHANRCV}, + [Afrom] {.c = fromtap, .v = &s, .op = CHANRCV}, + [Adev] {.c = kbdchan, .v = &s, .op = CHANRCV}, + [Ato] {.c = totap, .v = &s, .op = CHANNOP}, + [Ainp] {.c = nil, .v = &s, .op = CHANNOP}, + [Awatch]{.c = totap, .v = &watched, .op = CHANNOP}, + [NALT] {.op = CHANEND}, + }; cur = nil; watched = nil; diff --git a/sys/src/cmd/riow.c b/sys/src/cmd/riow.c index 787a87ad6..434b0d14d 100644 --- a/sys/src/cmd/riow.c +++ b/sys/src/cmd/riow.c @@ -2,6 +2,7 @@ #include <libc.h> #include <draw.h> #include <keyboard.h> +#include <ctype.h> typedef struct W W; @@ -24,6 +25,7 @@ struct W { Rectangle r; int vd; int flags; + int stickyforced; }; static int vd = 1; /* current virtual desktop */ @@ -86,12 +88,14 @@ wsupdate(void) w->r.max.y = atoi(t[3]); w->vd = -1; w->flags = 0; + w->stickyforced = 0; /* move over the current state of the window */ for(k = 0, seen = 0; k < wsn; k++){ if(ws[k].id == w->id){ w->vd = ws[k].vd; w->flags = ws[k].flags & ~(Fvisible|Fcurrent); + w->stickyforced = ws[k].stickyforced; if(w->flags & Ffullscreen) w->r = ws[k].r; seen = 1; @@ -117,17 +121,21 @@ wsupdate(void) } /* because a different program can run in any window we have to re-read */ - snprint(s, sizeof(s), "/dev/wsys/%d/label", w->id); w->flags &= ~Fsticky; - if((f = open(s, OREAD)) >= 0){ - n = read(f, s, sizeof(s)-1); - close(f); - if(n > 0){ - s[n] = 0; - for(k = 0; k < nelem(sticky) && sticky[k] != nil; k++){ - if(strcmp(sticky[k], s) == 0){ - w->flags |= Fsticky; - break; + if(w->stickyforced){ + w->flags |= Fsticky; + }else{ + snprint(s, sizeof(s), "/dev/wsys/%d/label", w->id); + if((f = open(s, OREAD)) >= 0){ + n = read(f, s, sizeof(s)-1); + close(f); + if(n > 0){ + s[n] = 0; + for(k = 0; k < nelem(sticky) && sticky[k] != nil; k++){ + if(strcmp(sticky[k], s) == 0){ + w->flags |= Fsticky; + break; + } } } } @@ -153,6 +161,7 @@ togglefullscreen(void) { int f; + wsupdate(); if(wcur == nil || (f = wwctl(wcur->id, OWRITE)) < 0) return; wcur->flags ^= Ffullscreen; @@ -166,8 +175,9 @@ togglefullscreen(void) static void togglesticky(void) { + wsupdate(); if(wcur != nil) - wcur->flags ^= Fsticky; + wcur->stickyforced ^= 1; } static void @@ -176,14 +186,15 @@ vdaction(int nvd) int f, wcurf; W *w; + if(vd == nvd) + return; + + wsupdate(); if(mod == Mmod4){ wcur = nil; wcurf = -1; vd2wcur[vd] = -1; for(w = ws; w < ws+wsn; w++){ - if((f = wwctl(w->id, OWRITE)) < 0) - continue; - if(w->flags & Fvisible) w->vd = vd; else if(w->vd == vd) @@ -192,24 +203,33 @@ vdaction(int nvd) if(w->flags & Fcurrent) vd2wcur[vd] = w->id; - if(w->vd != nvd && (w->flags & Fsticky) == 0){ - fprint(f, "hide"); - }else{ - fprint(f, "unhide"); - if(vd2wcur[nvd] == w->id && wcurf < 0){ - wcur = w; - wcurf = f; - f = -1; + if(w->vd == nvd && (w->flags & Fsticky) == 0){ + if((f = wwctl(w->id, OWRITE)) >= 0){ + fprint(f, "unhide"); + if(vd2wcur[nvd] == w->id && wcurf < 0){ + wcur = w; + wcurf = f; + }else + close(f); } } - if(f >= 0) - close(f); } + if(wcur != nil){ fprint(wcurf, "top"); fprint(wcurf, "current"); close(wcurf); } + + for(w = ws; w < ws+wsn; w++){ + if(w->vd != nvd && (w->flags & (Fsticky|Fvisible)) == Fvisible){ + if((f = wwctl(w->id, OWRITE)) >= 0){ + fprint(f, "hide"); + close(f); + } + } + } + vd = nvd; fprint(3, "%d\n", vd); }else if(mod == (Mmod4 | Mshift) && wcur != nil && wcur->vd != nvd){ @@ -228,6 +248,7 @@ arrowaction(int x, int y) { int f; + wsupdate(); if(wcur == nil || (f = wwctl(wcur->id, OWRITE)) < 0) return; @@ -258,6 +279,7 @@ cycleaction(int x, int y) int wcurid, i, f; W *w, *w₀; + wsupdate(); wcurid = wcur == nil ? -1 : wcur->id; cyclectx.x = x; cyclectx.y = y; @@ -286,49 +308,90 @@ cycleaction(int x, int y) wcur = w; } -static void -keyevent(Rune r) +static int +keyevent(char c, Rune r) { - wsupdate(); - - if(r == '\n') - spawn("window"); - else if(r == 'f') - togglefullscreen(); - else if(r == 's') - togglesticky(); - else if(r >= '0' && r <= '9') + if(c == 'c'){ + if(r == '\n' && mod == Mmod4){ + spawn("window"); + return 0; + } + if(r == 'f' && mod == Mmod4){ + togglefullscreen(); + return 0; + } + if(r == 's' && mod == Mmod4){ + togglesticky(); + return 0; + } + if(r == Kup){ + arrowaction(0, -1); + return 0; + } + if(r == Kdown){ + arrowaction(0, 1); + return 0; + } + if(r == Kleft){ + arrowaction(-1, 0); + return 0; + } + if(r == Kright){ + arrowaction(1, 0); + return 0; + } + if(r == 'h' && mod == Mmod4){ + cycleaction(-1, 0); + return 0; + } + if(r == 'l' && mod == Mmod4){ + cycleaction(1, 0); + return 0; + } + if(r == 'j' && mod == Mmod4){ + cycleaction(0, 1); + return 0; + } + if(r == 'k' && mod == Mmod4){ + cycleaction(0, -1); + return 0; + } + if(r >= '0' && r <= '9' && (mod & Mctl) == 0){ + vdaction(r - '0'); + return 0; + } + } + /* mod4 + shift + 1…0 yields a shifted value on 'c': workaround */ + if(c == 'k' && mod == (Mmod4|Mshift) && r >= '0' && r <= '9'){ vdaction(r - '0'); - else if(r == Kup) - arrowaction(0, -1); - else if(r == Kdown) - arrowaction(0, 1); - else if(r == Kleft) - arrowaction(-1, 0); - else if(r == Kright) - arrowaction(1, 0); - else if(r == 'h') - cycleaction(-1, 0); - else if(r == 'l') - cycleaction(1, 0); - else if(r == 'j') - cycleaction(0, 1); - else if(r == 'k') - cycleaction(0, -1); + return 0; + } + /* don't bother to properly deal with handling shifted digit keys */ + if((mod & Mshift) != 0 && (c == 'c' || c == 'k' || c == 'K')) + return ispunct(r) ? 0 : -1; + + return -1; } static void process(char *s) { - int n, o, oldmod; char b[128], *p; + int n, o; Rune r; - if(*s == 'K' && s[1] == 0) - mod = 0; - o = 0; b[o++] = *s; + if(*s == 'k' || *s == 'K'){ + mod = 0; + if(utfrune(s+1, Kmod4) != nil) + mod |= Mmod4; + if(utfrune(s+1, Kctl) != nil) + mod |= Mctl; + if(utfrune(s+1, Kshift) != nil) + mod |= Mshift; + } + for(p = s+1; *p != 0; p += n){ if((n = chartorune(&r, p)) == 1 && r == Runeerror){ /* bail out */ @@ -339,36 +402,10 @@ process(char *s) break; } - oldmod = mod; - - if(*s == 'c' && (mod & Mmod4) != 0){ - keyevent(r); - continue; - } - - if(*s == 'k'){ - if(r == Kmod4) - mod |= Mmod4; - else if(r == Kctl) - mod |= Mctl; - else if(r == Kshift) - mod |= Mshift; - else if(r >= '0' && r <= '9' && (mod & (Mshift|Mmod4)) == (Mshift|Mmod4)) - keyevent(r); - }else if(*s == 'K'){ - if(r == Kmod4) - mod &= ~Mmod4; - else if(r == Kctl) - mod &= ~Mctl; - else if(r == Kshift) - mod &= ~Mshift; + if((mod & Mmod4) == 0 || keyevent(*s, r) != 0){ + memmove(b+o, p, n); + o += n; } - - if((oldmod | mod) & Mmod4) - continue; - - memmove(b+o, p, n); - o += n; } /* all runes filtered out - ignore completely */ diff --git a/sys/src/cmd/vt/main.c b/sys/src/cmd/vt/main.c index c6ec70976..32743c792 100644 --- a/sys/src/cmd/vt/main.c +++ b/sys/src/cmd/vt/main.c @@ -299,6 +299,7 @@ threadmain(int argc, char **argv) if(rfork(RFENVG) < 0) sysfatal("rfork: %r"); + doquote = needsrcquote; quotefmtinstall(); notify(catch); atexit(shutdown); |