devcec.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * Coraid ethernet console — serial replacement.
  11. */
  12. #include "u.h"
  13. #include "../port/lib.h"
  14. #include "mem.h"
  15. #include "dat.h"
  16. #include "fns.h"
  17. #include "io.h"
  18. #include "ureg.h"
  19. #include "../port/error.h"
  20. #include "../port/netif.h"
  21. extern Dev cecdevtab;
  22. enum {
  23. Namelen = 128,
  24. Ncbuf = 8192,
  25. Ncmask = Ncbuf-1,
  26. Nconns = 20,
  27. Size = READSTR,
  28. };
  29. enum {
  30. Hdrsz = 18,
  31. Tinita = 0,
  32. Tinitb,
  33. Tinitc,
  34. Tdata,
  35. Tack,
  36. Tdiscover,
  37. Toffer,
  38. Treset,
  39. Tlast,
  40. Cunused = 0,
  41. Cinitb,
  42. Clogin,
  43. Copen,
  44. };
  45. static char *cstate[] = {
  46. "unused",
  47. "initb",
  48. "login",
  49. "open"
  50. };
  51. typedef struct {
  52. Chan *dc;
  53. Chan *cc;
  54. Dev *d;
  55. uint8_t ea[6];
  56. char path[32];
  57. } If;
  58. typedef struct {
  59. uint8_t dst[6];
  60. uint8_t src[6];
  61. uint8_t etype[2];
  62. uint8_t type;
  63. uint8_t conn;
  64. uint8_t seq;
  65. uint8_t len;
  66. uint8_t data[0x100];
  67. } Pkt;
  68. typedef struct {
  69. QLock;
  70. Lock;
  71. uchar ea[6]; /* along with cno, the key to the connection */
  72. uchar cno; /* connection number on remote host */
  73. uchar stalled; /* cectimer needs to kick it */
  74. int state; /* connection state */
  75. int idle; /* idle ticks */
  76. int to; /* ticks to timeout */
  77. int retries; /* remaining retries */
  78. Block *bp; /* unacked message */
  79. If *ifc; /* interface for this connection */
  80. uchar sndseq; /* sequence number of last sent message */
  81. uchar rcvseq; /* sequence number of last rcv'd message */
  82. char cbuf[Ncbuf]; /* curcular buffer */
  83. int r, w; /* indexes into cbuf */
  84. int pwi; /* index into passwd; */
  85. char passwd[32]; /* password typed by connection */
  86. } Conn;
  87. extern int parseether(uint8_t *, char *);
  88. extern Chan *chandial(char *, char *, char *, Chan **);
  89. enum {
  90. Qdir = 0,
  91. Qstat,
  92. Qctl,
  93. Qdbg,
  94. Qcfg,
  95. CMreset,
  96. CMsetshelf,
  97. CMsetname,
  98. CMtraceon,
  99. CMtraceoff,
  100. CMsetpasswd,
  101. CMcecon,
  102. CMcecoff,
  103. CMwrite,
  104. };
  105. static If ifs[4];
  106. static char name[Namelen];
  107. static int shelf = -1;
  108. static Conn conn[Nconns];
  109. static int tflag;
  110. static char passwd[Namelen];
  111. static int xmit;
  112. static int rsnd;
  113. static Rendez trendez;
  114. static int tcond;
  115. static uint8_t broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  116. static Dirtab cecdir[] = {
  117. ".", { Qdir, 0, QTDIR }, 0, DMDIR | 0555,
  118. "cecstat", { Qstat}, 1, 0444,
  119. "cecctl", { Qctl}, 1, 0777,
  120. // "cecctl", { Qctl}, 1, 0664,
  121. "cecdbg", { Qdbg }, 1, 0444,
  122. "ceccfg", { Qcfg }, 1, 0444,
  123. };
  124. static Cmdtab ceccmd[] = {
  125. CMsetname, "name", 2,
  126. CMtraceon, "traceon", 1,
  127. CMtraceoff, "traceoff", 1,
  128. CMsetpasswd, "password", 2,
  129. CMcecon, "cecon", 2,
  130. CMcecoff, "cecoff", 2,
  131. CMsetshelf, "shelf", 2,
  132. CMwrite, "write", -1,
  133. };
  134. /*
  135. * Avoid outputting debugging to ourselves. Assumes a serial port.
  136. */
  137. static int
  138. cecprint(char *fmt, ...)
  139. {
  140. char buf[PRINTSIZE];
  141. int n;
  142. va_list arg;
  143. va_start(arg, fmt);
  144. n = vseprint(buf, buf+sizeof buf, fmt, arg)-buf;
  145. va_end(arg);
  146. uartputs(buf, n);
  147. return n;
  148. }
  149. static void
  150. getaddr(char *path, uint8_t *ea)
  151. {
  152. char buf[6*2];
  153. int n;
  154. Chan *c;
  155. snprint(up->genbuf, sizeof up->genbuf, "%s/addr", path);
  156. c = namec(up->genbuf, Aopen, OREAD, 0);
  157. if(waserror()) {
  158. cclose(c);
  159. nexterror();
  160. }
  161. n = c->dev->read(c, buf, sizeof buf, 0);
  162. if(n != sizeof buf)
  163. error("getaddr");
  164. if(parseether(ea, buf) < 0)
  165. error("parseether failure");
  166. poperror();
  167. cclose(c);
  168. }
  169. static char *types[Tlast+1] = {
  170. "Tinita", "Tinitb", "Tinitc", "Tdata", "Tack",
  171. "Tdiscover", "Toffer", "Treset", "*GOK*",
  172. };
  173. static int
  174. cbget(Conn *cp)
  175. {
  176. int c;
  177. if(cp->r == cp->w)
  178. return -1;
  179. c = cp->cbuf[cp->r];
  180. cp->r = cp->r+1 & Ncmask;
  181. return c;
  182. }
  183. static void
  184. cbput(Conn *cp, int c)
  185. {
  186. if(cp->r == (cp->w+1 & Ncmask))
  187. return;
  188. cp->cbuf[cp->w] = c;
  189. cp->w = cp->w+1 & Ncmask;
  190. }
  191. static void
  192. trace(Block *bp)
  193. {
  194. uint type;
  195. Pkt *p;
  196. if(tflag == 0)
  197. return;
  198. p = (Pkt *)bp->rp;
  199. type = p->type;
  200. if(type > Treset)
  201. type = Treset+1;
  202. cecprint("%E > %E) seq %d, type %s, len %d, conn %d\n",
  203. p->src, p->dst, p->seq, types[type], p->len, p->conn);
  204. }
  205. static Block*
  206. sethdr(If *ifc, uint8_t *ea, Pkt **npp, int len)
  207. {
  208. Block *bp;
  209. Pkt *np;
  210. len += Hdrsz;
  211. if(len < 60)
  212. len = 60;
  213. bp = allocb(len);
  214. bp->wp = bp->rp+len;
  215. np = (Pkt *)bp->rp;
  216. memmove(np->dst, ea, 6);
  217. memmove(np->src, ifc->ea, 6);
  218. np->etype[0] = 0xbc;
  219. np->etype[1] = 0xbc;
  220. np->seq = 0;
  221. *npp = np;
  222. return bp;
  223. }
  224. static void
  225. send(Conn *cp, Block *bp)
  226. {
  227. Block *nbp;
  228. if(cp->bp != nil)
  229. panic("cecsend: cp->bp not nil\n");
  230. nbp = allocb(BLEN(bp));
  231. memmove(nbp->wp, bp->rp, BLEN(bp));
  232. nbp->wp += BLEN(bp);
  233. cp->bp = nbp;
  234. trace(bp);
  235. cp->ifc->d->bwrite(cp->ifc->dc, bp, 0);
  236. xmit++;
  237. cp->to = 4;
  238. cp->retries = 3;
  239. xmit++;
  240. }
  241. static void
  242. senddata(Conn *cp, void *data, int len)
  243. {
  244. Block *bp;
  245. Pkt *p;
  246. bp = sethdr(cp->ifc, cp->ea, &p, len);
  247. memmove(p->data, data, len);
  248. p->len = len;
  249. p->seq = ++cp->sndseq;
  250. p->conn = cp->cno;
  251. p->type = Tdata;
  252. send(cp, bp);
  253. }
  254. static void
  255. resend(Conn *cp)
  256. {
  257. Block *nbp;
  258. rsnd++;
  259. nbp = allocb(BLEN(cp->bp));
  260. memmove(nbp->wp, cp->bp->rp, BLEN(cp->bp));
  261. nbp->wp += BLEN(cp->bp);
  262. trace(nbp);
  263. cp->ifc->d->bwrite(cp->ifc->dc, nbp, 0);
  264. cp->to = 4;
  265. }
  266. static void
  267. reset(If *ifc, uint8_t conn)
  268. {
  269. Block *bp;
  270. Pkt *p;
  271. bp = sethdr(ifc, ifc->ea, &p, 0);
  272. p->type = Treset;
  273. p->conn = conn;
  274. trace(bp);
  275. ifc->d->bwrite(ifc->dc, bp, 0);
  276. }
  277. static void
  278. ack(Conn *cp)
  279. {
  280. if(cp->bp)
  281. freeb(cp->bp);
  282. cp->bp = 0;
  283. cp->to = 0;
  284. cp->retries = 0;
  285. }
  286. static void
  287. start(Conn *cp)
  288. {
  289. char buf[250];
  290. int n, c;
  291. if(cp->bp)
  292. return;
  293. ilock(cp);
  294. for(n = 0; n < sizeof buf; n++){
  295. if((c = cbget(cp)) == -1)
  296. break;
  297. buf[n] = c;
  298. }
  299. iunlock(cp);
  300. if(n != 0)
  301. senddata(cp, buf, n);
  302. }
  303. static void
  304. cecputs(char *str, int n)
  305. {
  306. int i, c, wake;
  307. Conn *cp;
  308. wake = 0;
  309. for(cp = conn; cp < conn+Nconns; cp++){
  310. ilock(cp);
  311. if(cp->state == Copen){
  312. for (i = 0; i < n; i++){
  313. c = str[i];
  314. if(c == 0)
  315. continue; /* BOTCH */
  316. if(c == '\n')
  317. cbput(cp, '\r');
  318. cbput(cp, c);
  319. }
  320. cp->stalled = 1;
  321. wake = 1;
  322. }
  323. iunlock(cp);
  324. }
  325. if(wake){
  326. tcond = 1;
  327. wakeup(&trendez);
  328. }
  329. }
  330. static void
  331. conputs(Conn *c, char *s)
  332. {
  333. for(; *s; s++)
  334. cbput(c, *s);
  335. }
  336. static int
  337. icansleep(void*)
  338. {
  339. return tcond != 0;
  340. }
  341. static void
  342. cectimer(void *)
  343. {
  344. Conn *cp;
  345. for(;;){
  346. tsleep(&trendez, icansleep, 0, 250);
  347. tcond = 0;
  348. for(cp = conn; cp < conn + Nconns; cp++){
  349. qlock(cp);
  350. if(cp->bp != nil){
  351. if(--cp->to <= 0){
  352. if(--cp->retries <= 0){
  353. freeb(cp->bp);
  354. cp->bp = 0;
  355. // cp->state = Cunused;
  356. }else
  357. resend(cp);
  358. }
  359. }else if(cp->stalled){
  360. cp->stalled = 0;
  361. start(cp);
  362. }
  363. qunlock(cp);
  364. }
  365. }
  366. }
  367. static int
  368. cecqlen(void*)
  369. {
  370. int n;
  371. Conn *c;
  372. n = 0;
  373. for(c = conn; c < conn+Nconns; c++){
  374. if(!canqlock(c))
  375. continue;
  376. if(c->bp)
  377. n += BLEN(c->bp);
  378. if(c->r > c->w)
  379. n += c->r-c->w;
  380. else
  381. n += c->w-c->r;
  382. qunlock(c);
  383. }
  384. if(n){
  385. tcond = 1;
  386. wakeup(&trendez);
  387. }
  388. return n;
  389. }
  390. static void
  391. discover(If *ifc, Pkt *p)
  392. {
  393. uint8_t *addr;
  394. Block *bp;
  395. Pkt *np;
  396. if(p)
  397. addr = p->src;
  398. else
  399. addr = broadcast;
  400. bp = sethdr(ifc, addr, &np, 0);
  401. np->type = Toffer;
  402. np->len = snprint((char *)np->data, sizeof np->data, "%d %s",
  403. shelf, name);
  404. trace(bp);
  405. ifc->d->bwrite(ifc->dc, bp, 0);
  406. }
  407. static Conn*
  408. connidx(int cno)
  409. {
  410. Conn *c;
  411. for(c = conn; c < conn + Nconns; c++)
  412. if(cno == c->cno){
  413. qlock(c);
  414. return c;
  415. }
  416. return nil;
  417. }
  418. static Conn*
  419. findconn(uint8_t *ea, uint8_t cno)
  420. {
  421. Conn *cp, *ncp;
  422. ncp = nil;
  423. for(cp = conn; cp < conn + Nconns; cp++){
  424. if(ncp == nil && cp->state == Cunused)
  425. ncp = cp;
  426. if(memcmp(ea, cp->ea, 6) == 0 && cno == cp->cno){
  427. qlock(cp);
  428. return cp;
  429. }
  430. }
  431. if(ncp != nil)
  432. qlock(ncp);
  433. return ncp;
  434. }
  435. static void
  436. checkpw(Conn *cp, char *str, int len)
  437. {
  438. int i, c;
  439. if(passwd[0] == 0)
  440. return;
  441. for(i = 0; i < len; i++){
  442. c = str[i];
  443. if(c != '\n' && c != '\r'){
  444. if(cp->pwi < (sizeof cp->passwd)-1)
  445. cp->passwd[cp->pwi++] = c;
  446. cbput(cp, '#');
  447. cecprint("%c", c);
  448. continue;
  449. }
  450. /* is newline; check password */
  451. cp->passwd[cp->pwi] = 0;
  452. if(strcmp(cp->passwd, passwd) == 0){
  453. cp->state = Copen;
  454. cp->pwi = 0;
  455. print("\r\n%E logged in\r\n", cp->ea);
  456. }else{
  457. conputs(cp, "\r\nBad password\r\npassword: ");
  458. cp->pwi = 0;
  459. }
  460. }
  461. start(cp);
  462. }
  463. static void
  464. incoming(Conn *cp, If *ifc, Pkt *p)
  465. {
  466. int i;
  467. Block *bp;
  468. Pkt *np;
  469. /* ack it no matter what its sequence number */
  470. bp = sethdr(ifc, p->src, &np, 0);
  471. np->type = Tack;
  472. np->seq = p->seq;
  473. np->conn = cp->cno;
  474. np->len = 0;
  475. trace(bp);
  476. ifc->d->bwrite(ifc->dc, bp, 0);
  477. if(cp->state == Cunused){
  478. /* connection */
  479. discover(ifc, p);
  480. return;
  481. }
  482. if(p->seq == cp->rcvseq)
  483. return;
  484. cp->rcvseq = p->seq;
  485. if(cp->state == Copen){
  486. for (i = 0; i < p->len; i++)
  487. kbdcr2nl(nil, (char)p->data[i]);
  488. }else if(cp->state == Clogin)
  489. checkpw(cp, (char *)p->data, p->len);
  490. }
  491. static void
  492. inita(Conn *ncp, If *ifc, Pkt *p)
  493. {
  494. Block *bp;
  495. Pkt *np;
  496. ncp->ifc = ifc;
  497. ncp->state = Cinitb;
  498. memmove(ncp->ea, p->src, 6);
  499. ncp->cno = p->conn;
  500. bp = sethdr(ifc, p->src, &np, 0);
  501. np->type = Tinitb;
  502. np->conn = ncp->cno;
  503. np->len = 0;
  504. send(ncp, bp);
  505. }
  506. static void
  507. cecrdr(void *vp)
  508. {
  509. Block *bp;
  510. Conn *cp;
  511. If *ifc;
  512. Pkt *p;
  513. ifc = vp;
  514. if(waserror())
  515. goto exit;
  516. discover(ifc, 0);
  517. for(;;){
  518. bp = ifc->d->bread(ifc->dc, 1514, 0); // do we care about making the MTU non magic?
  519. if(bp == nil)
  520. nexterror();
  521. p = (Pkt *)bp->rp;
  522. if(p->etype[0] != 0xbc || p->etype[1] != 0xbc){
  523. freeb(bp);
  524. continue;
  525. }
  526. trace(bp);
  527. cp = findconn(p->src, p->conn);
  528. if(cp == nil){
  529. cecprint("cec: out of connection structures\n");
  530. freeb(bp);
  531. continue;
  532. }
  533. if (waserror()){
  534. freeb(bp);
  535. qunlock(cp);
  536. continue;
  537. }
  538. switch(p->type){
  539. case Tinita:
  540. if(cp->bp){
  541. cecprint("cec: reset with bp!? ask quanstro\n");
  542. freeb(cp->bp);
  543. cp->bp = 0;
  544. }
  545. inita(cp, ifc, p);
  546. break;
  547. case Tinitb:
  548. cecprint("cec: unexpected initb\n");
  549. break;
  550. case Tinitc:
  551. if(cp->state == Cinitb){
  552. ack(cp);
  553. if(cp->passwd[0]){
  554. cp->state = Clogin;
  555. conputs(cp, "password: ");
  556. start(cp);
  557. }else
  558. cp->state = Copen;
  559. }
  560. break;
  561. case Tdata:
  562. incoming(cp, ifc, p);
  563. break;
  564. case Tack:
  565. if(cp->state == Clogin || cp->state == Copen){
  566. ack(cp);
  567. start(cp);
  568. }
  569. break;
  570. case Tdiscover:
  571. discover(ifc, p);
  572. break;
  573. case Toffer:
  574. // cecprint("cec: unexpected offer\n"); from ourselves.
  575. break;
  576. case Treset:
  577. if(cp->bp)
  578. freeb(cp->bp);
  579. cp->bp = 0;
  580. cp->state = Cunused;
  581. break;
  582. default:
  583. cecprint("bad cec type: %d\n", p->type);
  584. break;
  585. }
  586. nexterror();
  587. }
  588. exit:
  589. for(cp = conn; cp < conn+nelem(conn); cp++)
  590. if(cp->ifc == ifc){
  591. if(cp->bp)
  592. freeb(cp->bp);
  593. memset(cp, 0, sizeof *cp);
  594. break;
  595. }
  596. memset(ifc, 0, sizeof *ifc);
  597. pexit("cec exiting", 1);
  598. }
  599. static Chan *
  600. cecattach(char *spec)
  601. {
  602. Chan *c;
  603. static QLock q;
  604. static int inited;
  605. qlock(&q);
  606. if(inited == 0){
  607. kproc("cectimer", cectimer, nil);
  608. inited++;
  609. }
  610. qunlock(&q);
  611. c = devattach(L'©', spec);
  612. c->qid.path = Qdir;
  613. return c;
  614. }
  615. static Walkqid*
  616. cecwalk(Chan *c, Chan *nc, char **name, int nname)
  617. {
  618. return devwalk(c, nc, name, nname, cecdir, nelem(cecdir), devgen);
  619. }
  620. static int32_t
  621. cecstat(Chan *c, uint8_t *dp, int32_t n)
  622. {
  623. return devstat(c, dp, n, cecdir, nelem(cecdir), devgen);
  624. }
  625. static Chan*
  626. cecopen(Chan *c, int omode)
  627. {
  628. return devopen(c, omode, cecdir, nelem(cecdir), devgen);
  629. }
  630. static void
  631. cecclose(Chan*)
  632. {
  633. }
  634. static int32_t
  635. cecread(Chan *c, void *a, int32_t n, int64_t offset)
  636. {
  637. char *p;
  638. int j;
  639. Conn *cp;
  640. If *ifc;
  641. switch((int)c->qid.path){
  642. case Qdir:
  643. return devdirread(c, a, n, cecdir, nelem(cecdir), devgen);
  644. case Qstat:
  645. p = smalloc(Size);
  646. j = 0;
  647. for(cp = conn; cp < conn+Nconns; cp++)
  648. if(cp->state != Cunused)
  649. j += snprint(p+j, Size-j,
  650. "%E %3d %-6s %12d %d %d %.8lux\n",
  651. cp->ea, cp->cno, cstate[cp->state], cp->idle,
  652. cp->to, cp->retries, (uintptr)cp->bp);
  653. n = readstr(offset, a, n, p);
  654. free(p);
  655. return n;
  656. case Qdbg:
  657. cecprint("xmit %d, rsnd %d\n", xmit, rsnd);
  658. return 0;
  659. case Qcfg:
  660. case Qctl:
  661. p = smalloc(Size);
  662. j = 0;
  663. for(ifc = ifs; ifc < ifs+nelem(ifs); ifc++)
  664. if(ifc->d)
  665. j += snprint(p+j, Size-j, "%s\n", ifc->path);
  666. n = readstr(offset, a, n, p);
  667. free(p);
  668. return n;
  669. }
  670. error(Egreg);
  671. return 0;
  672. }
  673. /*
  674. static void
  675. cecfixup(void)
  676. {
  677. char *p;
  678. int len;
  679. p = malloc(128*1024);
  680. snprint(p, 6, "write ");
  681. len = readfile("/dev/kmesg", p+6, 128*1024-6);
  682. writefile("#©/cecctl", p, len+6);
  683. free(p);
  684. }
  685. */
  686. static void
  687. cecon(char *path)
  688. {
  689. char buf[64];
  690. uint8_t ea[6];
  691. Chan *dc, *cc;
  692. If *ifc, *nifc;
  693. nifc = nil;
  694. for(ifc = ifs; ifc < ifs+nelem(ifs); ifc++)
  695. if(ifc->d == nil)
  696. nifc = ifc;
  697. else if(strcmp(ifc->path, path) == 0)
  698. return;
  699. ifc = nifc;
  700. if(ifc == nil)
  701. error("out of interface structures");
  702. getaddr(path, ea);
  703. snprint(buf, sizeof buf, "%s!0xbcbc", path);
  704. dc = chandial(buf, nil, nil, &cc);
  705. if(dc == nil || cc == nil){
  706. if (cc)
  707. cclose(cc);
  708. if (dc)
  709. cclose(dc);
  710. snprint(up->genbuf, sizeof up->genbuf, "can't dial %s", buf);
  711. error(up->genbuf);
  712. }
  713. ifc->d = cc->dev;
  714. ifc->cc = cc;
  715. ifc->dc = dc;
  716. strncpy(ifc->path, path, sizeof ifc->path);
  717. memmove(ifc->ea, ea, 6);
  718. snprint(up->genbuf, sizeof up->genbuf, "cec:%s", path);
  719. kproc(up->genbuf, cecrdr, ifc);
  720. }
  721. static void
  722. cecoff(char *path)
  723. {
  724. int all, n;
  725. If *ifc, *e;
  726. all = strcmp(path, "*") == 0;
  727. n = 0;
  728. ifc = ifs;
  729. e = ifc+nelem(ifs);
  730. for(; ifc < e; ifc++)
  731. if(ifc->d && (all || strcmp(path, ifc->path) == 0)){
  732. cclose(ifc->cc);
  733. cclose(ifc->dc);
  734. memset(ifc, 0, sizeof *ifc);
  735. n++;
  736. }
  737. if(all + n == 0)
  738. error("cec not found");
  739. }
  740. static void
  741. rst(Conn *c)
  742. {
  743. if(c == nil)
  744. error("no such index");
  745. if(c->bp)
  746. freeb(c->bp);
  747. c->bp = 0;
  748. c->state = Cunused;
  749. qunlock(c);
  750. }
  751. static int32_t
  752. cecwrite(Chan *c, void *a, int32_t n, int64_t)
  753. {
  754. Cmdbuf *cb;
  755. Cmdtab *cp;
  756. if(c->qid.path == Qctl){
  757. cb = parsecmd(a, n);
  758. if(waserror()){
  759. free(cb);
  760. nexterror();
  761. }
  762. cp = lookupcmd(cb, ceccmd, nelem(ceccmd));
  763. switch(cp->index){
  764. case CMsetname:
  765. strecpy(name, name+sizeof name-1, cb->f[1]);
  766. break;
  767. case CMtraceon:
  768. tflag = 1;
  769. break;
  770. case CMtraceoff:
  771. tflag = 0;
  772. break;
  773. case CMsetpasswd:
  774. strcpy(passwd, cb->f[1]);
  775. break;
  776. case CMcecon:
  777. cecon(cb->f[1]);
  778. break;
  779. case CMcecoff:
  780. cecoff(cb->f[1]);
  781. break;
  782. case CMsetshelf:
  783. shelf = atoi(cb->f[1]);
  784. break;
  785. case CMwrite:
  786. cecputs((char*)a+6,n-6);
  787. break;
  788. case CMreset:
  789. rst(connidx(atoi(cb->f[1])));
  790. break;
  791. default:
  792. cmderror(cb, "bad control message");
  793. break;
  794. }
  795. free(cb);
  796. poperror();
  797. return n;
  798. }
  799. error(Egreg);
  800. return 0;
  801. }
  802. static void
  803. cecinit(void)
  804. {
  805. addconsdev(nil, cecputs, -1, 0);
  806. }
  807. Dev cecdevtab = {
  808. L'©',
  809. "cec",
  810. devreset,
  811. cecinit,
  812. devshutdown,
  813. cecattach,
  814. cecwalk,
  815. cecstat,
  816. cecopen,
  817. devcreate,
  818. cecclose,
  819. cecread,
  820. devbread,
  821. cecwrite,
  822. devbwrite,
  823. devremove,
  824. devwstat,
  825. devpower,
  826. devconfig,
  827. };