devcec.c 15 KB

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