apm.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  1. #include <u.h>
  2. #include <libc.h>
  3. #include </386/include/ureg.h>
  4. typedef struct Ureg Ureg;
  5. #include <auth.h>
  6. #include <fcall.h>
  7. #include <thread.h>
  8. #include <9p.h>
  9. enum {
  10. /* power mgmt event codes */
  11. NotifyStandbyRequest = 0x0001,
  12. NotifySuspendRequest = 0x0002,
  13. NotifyNormalResume = 0x0003,
  14. NotifyCriticalResume = 0x0004,
  15. NotifyBatteryLow = 0x0005,
  16. NotifyPowerStatusChange = 0x0006,
  17. NotifyUpdateTime = 0x0007,
  18. NotifyCriticalSuspend = 0x0008,
  19. NotifyUserStandbyRequest = 0x0009,
  20. NotifyUserSuspendRequest = 0x000A,
  21. NotifyStandbyResume = 0x000B,
  22. NotifyCapabilitiesChange = 0x000C,
  23. /* power device ids: add device number or All */
  24. DevBios = 0x0000,
  25. DevAll = 0x0001,
  26. DevDisplay = 0x0100,
  27. DevStorage = 0x0200,
  28. DevLpt = 0x0300,
  29. DevEia = 0x0400,
  30. DevNetwork = 0x0500,
  31. DevPCMCIA = 0x0600,
  32. DevBattery = 0x8000,
  33. All = 0x00FF,
  34. DevMask = 0xFF00,
  35. /* power states */
  36. PowerEnabled = 0x0000,
  37. PowerStandby = 0x0001,
  38. PowerSuspend = 0x0002,
  39. PowerOff = 0x0003,
  40. /* apm commands */
  41. CmdInstallationCheck = 0x5300,
  42. CmdRealModeConnect = 0x5301,
  43. CmdProtMode16Connect = 0x5302,
  44. CmdProtMode32Connect = 0x5303,
  45. CmdDisconnect = 0x5304,
  46. CmdCpuIdle = 0x5305,
  47. CmdCpuBusy = 0x5306,
  48. CmdSetPowerState = 0x5307,
  49. CmdSetPowerMgmt = 0x5308,
  50. DisablePowerMgmt = 0x0000, /* CX */
  51. EnablePowerMgmt = 0x0001,
  52. CmdRestoreDefaults = 0x5309,
  53. CmdGetPowerStatus = 0x530A,
  54. CmdGetPMEvent = 0x530B,
  55. CmdGetPowerState = 0x530C,
  56. CmdGetPowerMgmt = 0x530D,
  57. CmdDriverVersion = 0x530E,
  58. /* like CmdDisconnect but doesn't lose the interface */
  59. CmdGagePowerMgmt = 0x530F,
  60. DisengagePowerMgmt = 0x0000, /* CX */
  61. EngagePowerManagemenet = 0x0001,
  62. CmdGetCapabilities = 0x5310,
  63. CapStandby = 0x0001,
  64. CapSuspend = 0x0002,
  65. CapTimerResumeStandby = 0x0004,
  66. CapTimerResumeSuspend = 0x0008,
  67. CapRingResumeStandby = 0x0010,
  68. CapRingResumeSuspend = 0x0020,
  69. CapPcmciaResumeStandby = 0x0040,
  70. CapPcmciaResumeSuspend = 0x0080,
  71. CapSlowCpu = 0x0100,
  72. CmdResumeTimer = 0x5311,
  73. DisableResumeTimer = 0x00, /* CL */
  74. GetResumeTimer = 0x01,
  75. SetResumeTimer = 0x02,
  76. CmdResumeOnRing = 0x5312,
  77. DisableResumeOnRing = 0x0000, /* CX */
  78. EnableResumeOnRing = 0x0001,
  79. GetResumeOnRing = 0x0002,
  80. CmdTimerRequests = 0x5313,
  81. DisableTimerRequests = 0x0000, /* CX */
  82. EnableTimerRequests = 0x0001,
  83. GetTimerRequests = 0x0002,
  84. };
  85. static char* eventstr[] = {
  86. [NotifyStandbyRequest] "system standby request",
  87. [NotifySuspendRequest] "system suspend request",
  88. [NotifyNormalResume] "normal resume",
  89. [NotifyCriticalResume] "critical resume",
  90. [NotifyBatteryLow] "battery low",
  91. [NotifyPowerStatusChange] "power status change",
  92. [NotifyUpdateTime] "update time",
  93. [NotifyCriticalSuspend] "critical suspend",
  94. [NotifyUserStandbyRequest] "user standby request",
  95. [NotifyUserSuspendRequest] "user suspend request",
  96. [NotifyCapabilitiesChange] "capabilities change",
  97. };
  98. static char*
  99. apmevent(int e)
  100. {
  101. static char buf[32];
  102. if(0 <= e && e < nelem(eventstr) && eventstr[e])
  103. return eventstr[e];
  104. sprint(buf, "event 0x%ux", (uint)e);
  105. return buf;
  106. }
  107. static char *error[256] = {
  108. [0x01] "power mgmt disabled",
  109. [0x02] "real mode connection already established",
  110. [0x03] "interface not connected",
  111. [0x05] "16-bit protected mode connection already established",
  112. [0x06] "16-bit protected mode interface not supported",
  113. [0x07] "32-bit protected mode interface already established",
  114. [0x08] "32-bit protected mode interface not supported",
  115. [0x09] "unrecognized device id",
  116. [0x0A] "parameter value out of range",
  117. [0x0B] "interface not engaged",
  118. [0x0C] "function not supported",
  119. [0x0D] "resume timer disabled",
  120. [0x60] "unable to enter requestsed state",
  121. [0x80] "no power mgmt events pending",
  122. [0x86] "apm not present",
  123. };
  124. static char*
  125. apmerror(int id)
  126. {
  127. char *e;
  128. static char buf[64];
  129. if(e = error[id&0xFF])
  130. return e;
  131. sprint(buf, "unknown error %x", id);
  132. return buf;
  133. }
  134. QLock apmlock;
  135. int apmdebug;
  136. static int
  137. _apmcall(int fd, Ureg *u)
  138. {
  139. if(apmdebug) fprint(2, "call ax 0x%lux bx 0x%lux cx 0x%lux\n",
  140. u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF);
  141. seek(fd, 0, 0);
  142. if(write(fd, u, sizeof *u) != sizeof *u)
  143. return -1;
  144. seek(fd, 0, 0);
  145. if(read(fd, u, sizeof *u) != sizeof *u)
  146. return -1;
  147. if(apmdebug) fprint(2, "flags 0x%lux ax 0x%lux bx 0x%lux cx 0x%lux\n",
  148. u->flags&0xFFFF, u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF);
  149. if(u->flags & 1) { /* carry flag */
  150. werrstr("%s", apmerror(u->ax>>8));
  151. return -1;
  152. }
  153. return 0;
  154. }
  155. static int
  156. apmcall(int fd, Ureg *u)
  157. {
  158. int r;
  159. qlock(&apmlock);
  160. r = _apmcall(fd, u);
  161. qunlock(&apmlock);
  162. return r;
  163. }
  164. typedef struct Apm Apm;
  165. typedef struct Battery Battery;
  166. struct Battery {
  167. int status;
  168. int percent;
  169. int time;
  170. };
  171. enum {
  172. Mbattery = 4,
  173. };
  174. struct Apm {
  175. int fd;
  176. int verhi;
  177. int verlo;
  178. int acstatus;
  179. int nbattery;
  180. int capabilities;
  181. Battery battery[Mbattery];
  182. };
  183. enum {
  184. AcUnknown = 0, /* Apm.acstatus */
  185. AcOffline,
  186. AcOnline,
  187. AcBackup,
  188. BatteryUnknown = 0, /* Battery.status */
  189. BatteryHigh,
  190. BatteryLow,
  191. BatteryCritical,
  192. BatteryCharging,
  193. };
  194. static char*
  195. acstatusstr[] = {
  196. [AcUnknown] "unknown",
  197. [AcOffline] "offline",
  198. [AcOnline] "online",
  199. [AcBackup] "backup",
  200. };
  201. static char*
  202. batterystatusstr[] = {
  203. [BatteryUnknown] "unknown",
  204. [BatteryHigh] "high",
  205. [BatteryLow] "low",
  206. [BatteryCritical] "critical",
  207. [BatteryCharging] "charging",
  208. };
  209. static char*
  210. powerstatestr[] = {
  211. [PowerOff] "off",
  212. [PowerSuspend] "suspend",
  213. [PowerStandby] "standby",
  214. [PowerEnabled] "on",
  215. };
  216. static char*
  217. xstatus(char **str, int nstr, int x)
  218. {
  219. if(0 <= x && x < nstr && str[x])
  220. return str[x];
  221. return "unknown";
  222. }
  223. static char*
  224. batterystatus(int b)
  225. {
  226. return xstatus(batterystatusstr, nelem(batterystatusstr), b);
  227. }
  228. static char*
  229. powerstate(int s)
  230. {
  231. return xstatus(powerstatestr, nelem(powerstatestr), s);
  232. }
  233. static char*
  234. acstatus(int a)
  235. {
  236. return xstatus(acstatusstr, nelem(acstatusstr), a);
  237. }
  238. static int
  239. apmversion(Apm *apm)
  240. {
  241. Ureg u;
  242. u.ax = CmdDriverVersion;
  243. u.bx = 0x0000;
  244. u.cx = 0x0102;
  245. if(apmcall(apm->fd, &u) < 0)
  246. return -1;
  247. apm->verhi = u.cx>>8;
  248. apm->verlo = u.cx & 0xFF;
  249. return u.cx;
  250. }
  251. static int
  252. apmcpuidle(Apm *apm)
  253. {
  254. Ureg u;
  255. u.ax = CmdCpuIdle;
  256. return apmcall(apm->fd, &u);
  257. }
  258. static int
  259. apmcpubusy(Apm *apm)
  260. {
  261. Ureg u;
  262. u.ax = CmdCpuBusy;
  263. return apmcall(apm->fd, &u);
  264. }
  265. static int
  266. apmsetpowerstate(Apm *apm, int dev, int state)
  267. {
  268. Ureg u;
  269. u.ax = CmdSetPowerState;
  270. u.bx = dev;
  271. u.cx = state;
  272. return apmcall(apm->fd, &u);
  273. }
  274. static int
  275. apmsetpowermgmt(Apm *apm, int dev, int state)
  276. {
  277. Ureg u;
  278. u.ax = CmdSetPowerMgmt;
  279. u.bx = dev;
  280. u.cx = state;
  281. return apmcall(apm->fd, &u);
  282. }
  283. static int
  284. apmrestoredefaults(Apm *apm, int dev)
  285. {
  286. Ureg u;
  287. u.ax = CmdRestoreDefaults;
  288. u.bx = dev;
  289. return apmcall(apm->fd, &u);
  290. }
  291. static int
  292. apmgetpowerstatus(Apm *apm, int dev)
  293. {
  294. Battery *b;
  295. Ureg u;
  296. if(dev == DevAll)
  297. b = &apm->battery[0];
  298. else if((dev & DevMask) == DevBattery) {
  299. if(dev - DevBattery < nelem(apm->battery))
  300. b = &apm->battery[dev - DevBattery];
  301. else
  302. b = nil;
  303. } else {
  304. werrstr("bad device number");
  305. return -1;
  306. }
  307. u.ax = CmdGetPowerStatus;
  308. u.bx = dev;
  309. if(apmcall(apm->fd, &u) < 0)
  310. return -1;
  311. if((dev & DevMask) == DevBattery)
  312. apm->nbattery = u.si;
  313. switch(u.bx>>8) {
  314. case 0x00:
  315. apm->acstatus = AcOffline;
  316. break;
  317. case 0x01:
  318. apm->acstatus = AcOnline;
  319. break;
  320. case 0x02:
  321. apm->acstatus = AcBackup;
  322. break;
  323. default:
  324. apm->acstatus = AcUnknown;
  325. break;
  326. }
  327. if(b != nil) {
  328. switch(u.bx&0xFF) {
  329. case 0x00:
  330. b->status = BatteryHigh;
  331. break;
  332. case 0x01:
  333. b->status = BatteryLow;
  334. break;
  335. case 0x02:
  336. b->status = BatteryCritical;
  337. break;
  338. case 0x03:
  339. b->status = BatteryCharging;
  340. break;
  341. default:
  342. b->status = BatteryUnknown;
  343. break;
  344. }
  345. if((u.cx & 0xFF) == 0xFF)
  346. b->percent = -1;
  347. else
  348. b->percent = u.cx & 0xFF;
  349. if((u.dx&0xFFFF) == 0xFFFF)
  350. b->time = -1;
  351. else if(u.dx & 0x8000)
  352. b->time = 60*(u.dx & 0x7FFF);
  353. else
  354. b->time = u.dx & 0x7FFF;
  355. }
  356. return 0;
  357. }
  358. static int
  359. apmgetevent(Apm *apm)
  360. {
  361. Ureg u;
  362. u.ax = CmdGetPMEvent;
  363. u.bx = 0;
  364. u.cx = 0;
  365. //when u.bx == NotifyNormalResume or NotifyCriticalResume,
  366. //u.cx & 1 indicates PCMCIA socket was on while suspended,
  367. //u.cx & 1 == 0 indicates was off.
  368. if(apmcall(apm->fd, &u) < 0)
  369. return -1;
  370. return u.bx;
  371. }
  372. static int
  373. apmgetpowerstate(Apm *apm, int dev)
  374. {
  375. Ureg u;
  376. u.ax = CmdGetPowerState;
  377. u.bx = dev;
  378. u.cx = 0;
  379. if(apmcall(apm->fd, &u) < 0)
  380. return -1;
  381. return u.cx;
  382. }
  383. static int
  384. apmgetpowermgmt(Apm *apm, int dev)
  385. {
  386. Ureg u;
  387. u.ax = CmdGetPowerMgmt;
  388. u.bx = dev;
  389. if(apmcall(apm->fd, &u) < 0)
  390. return -1;
  391. return u.cx;
  392. }
  393. static int
  394. apmgetcapabilities(Apm *apm)
  395. {
  396. Ureg u;
  397. u.ax = CmdGetCapabilities;
  398. u.bx = DevBios;
  399. if(apmcall(apm->fd, &u) < 0)
  400. return -1;
  401. apm->nbattery = u.bx & 0xFF;
  402. apm->capabilities &= ~0xFFFF;
  403. apm->capabilities |= u.cx;
  404. return 0;
  405. }
  406. static int
  407. apminstallationcheck(Apm *apm)
  408. {
  409. Ureg u;
  410. u.ax = CmdInstallationCheck;
  411. u.bx = DevBios;
  412. if(apmcall(apm->fd, &u) < 0)
  413. return -1;
  414. if(u.cx & 0x0004)
  415. apm->capabilities |= CapSlowCpu;
  416. else
  417. apm->capabilities &= ~CapSlowCpu;
  418. return 0;
  419. }
  420. void
  421. apmsetdisplaystate(Apm *apm, int s)
  422. {
  423. apmsetpowerstate(apm, DevDisplay, s);
  424. }
  425. void
  426. apmblank(Apm *apm)
  427. {
  428. apmsetdisplaystate(apm, PowerStandby);
  429. }
  430. void
  431. apmunblank(Apm *apm)
  432. {
  433. apmsetdisplaystate(apm, PowerEnabled);
  434. }
  435. void
  436. apmsuspend(Apm *apm)
  437. {
  438. apmsetpowerstate(apm, DevAll, PowerSuspend);
  439. }
  440. Apm apm;
  441. void
  442. powerprint(void)
  443. {
  444. print("%s", ctime(time(0)));
  445. if(apmgetpowerstatus(&apm, DevAll) == 0) {
  446. print("%d batteries\n", apm.nbattery);
  447. print("battery 0: status %s percent %d time %d:%.2d\n",
  448. batterystatus(apm.battery[0].status), apm.battery[0].percent,
  449. apm.battery[0].time/60, apm.battery[0].time%60);
  450. }
  451. }
  452. void*
  453. erealloc(void *v, ulong n)
  454. {
  455. v = realloc(v, n);
  456. if(v == nil)
  457. sysfatal("out of memory reallocating %lud", n);
  458. setmalloctag(v, getcallerpc(&v));
  459. return v;
  460. }
  461. void*
  462. emalloc(ulong n)
  463. {
  464. void *v;
  465. v = malloc(n);
  466. if(v == nil)
  467. sysfatal("out of memory allocating %lud", n);
  468. memset(v, 0, n);
  469. setmalloctag(v, getcallerpc(&n));
  470. return v;
  471. }
  472. char*
  473. estrdup(char *s)
  474. {
  475. int l;
  476. char *t;
  477. if (s == nil)
  478. return nil;
  479. l = strlen(s)+1;
  480. t = emalloc(l);
  481. memcpy(t, s, l);
  482. setmalloctag(t, getcallerpc(&s));
  483. return t;
  484. }
  485. char*
  486. estrdupn(char *s, int n)
  487. {
  488. int l;
  489. char *t;
  490. l = strlen(s);
  491. if(l > n)
  492. l = n;
  493. t = emalloc(l+1);
  494. memmove(t, s, l);
  495. t[l] = '\0';
  496. setmalloctag(t, getcallerpc(&s));
  497. return t;
  498. }
  499. enum {
  500. Qroot = 0,
  501. Qevent,
  502. Qbattery,
  503. Qctl,
  504. };
  505. static void rootread(Req*);
  506. static void eventread(Req*);
  507. static void ctlread(Req*);
  508. static void ctlwrite(Req*);
  509. static void batteryread(Req*);
  510. typedef struct Dfile Dfile;
  511. struct Dfile {
  512. Qid qid;
  513. char *name;
  514. ulong mode;
  515. void (*read)(Req*);
  516. void (*write)(Req*);
  517. };
  518. Dfile dfile[] = {
  519. { {Qroot,0,QTDIR}, "/", DMDIR|0555, rootread, nil, },
  520. { {Qevent}, "event", 0444, eventread, nil, },
  521. { {Qbattery}, "battery", 0444, batteryread, nil, },
  522. { {Qctl}, "ctl", 0666, ctlread, ctlwrite, },
  523. };
  524. static int
  525. fillstat(ulong path, Dir *d, int doalloc)
  526. {
  527. int i;
  528. for(i=0; i<nelem(dfile); i++)
  529. if(path==dfile[i].qid.path)
  530. break;
  531. if(i==nelem(dfile))
  532. return -1;
  533. memset(d, 0, sizeof *d);
  534. d->uid = doalloc ? estrdup("apm") : "apm";
  535. d->gid = doalloc ? estrdup("apm") : "apm";
  536. d->length = 0;
  537. d->name = doalloc ? estrdup(dfile[i].name) : dfile[i].name;
  538. d->mode = dfile[i].mode;
  539. d->atime = d->mtime = time(0);
  540. d->qid = dfile[i].qid;
  541. return 0;
  542. }
  543. static char*
  544. fswalk1(Fid *fid, char *name, Qid *qid)
  545. {
  546. int i;
  547. if(strcmp(name, "..")==0){
  548. *qid = dfile[0].qid;
  549. fid->qid = *qid;
  550. return nil;
  551. }
  552. for(i=1; i<nelem(dfile); i++){ /* i=1: 0 is root dir */
  553. if(strcmp(dfile[i].name, name)==0){
  554. *qid = dfile[i].qid;
  555. fid->qid = *qid;
  556. return nil;
  557. }
  558. }
  559. return "file does not exist";
  560. }
  561. static void
  562. fsopen(Req *r)
  563. {
  564. switch((ulong)r->fid->qid.path){
  565. case Qroot:
  566. r->fid->aux = (void*)0;
  567. respond(r, nil);
  568. return;
  569. case Qevent:
  570. case Qbattery:
  571. if(r->ifcall.mode == OREAD){
  572. respond(r, nil);
  573. return;
  574. }
  575. break;
  576. case Qctl:
  577. if((r->ifcall.mode&~(OTRUNC|OREAD|OWRITE|ORDWR)) == 0){
  578. respond(r, nil);
  579. return;
  580. }
  581. break;
  582. }
  583. respond(r, "permission denied");
  584. return;
  585. }
  586. static void
  587. fsstat(Req *r)
  588. {
  589. fillstat(r->fid->qid.path, &r->d, 1);
  590. respond(r, nil);
  591. }
  592. static void
  593. fsread(Req *r)
  594. {
  595. dfile[r->fid->qid.path].read(r);
  596. }
  597. static void
  598. fswrite(Req *r)
  599. {
  600. dfile[r->fid->qid.path].write(r);
  601. }
  602. static void
  603. rootread(Req *r)
  604. {
  605. int n, offset;
  606. char *p, *ep;
  607. Dir d;
  608. if(r->ifcall.offset == 0)
  609. offset = 0;
  610. else
  611. offset = (int)r->fid->aux;
  612. p = r->ofcall.data;
  613. ep = r->ofcall.data+r->ifcall.count;
  614. if(offset == 0) /* skip root */
  615. offset = 1;
  616. for(; p+2 < ep; p+=n){
  617. if(fillstat(offset, &d, 0) < 0)
  618. break;
  619. n = convD2M(&d, (uchar*)p, ep-p);
  620. if(n <= BIT16SZ)
  621. break;
  622. offset++;
  623. }
  624. r->fid->aux = (void*)offset;
  625. r->ofcall.count = p - r->ofcall.data;
  626. respond(r, nil);
  627. }
  628. static void
  629. batteryread(Req *r)
  630. {
  631. char buf[Mbattery*80], *ep, *p;
  632. int i;
  633. apmgetpowerstatus(&apm, DevAll);
  634. p = buf;
  635. ep = buf+sizeof buf;
  636. *p = '\0'; /* could be no batteries */
  637. for(i=0; i<apm.nbattery && i<Mbattery; i++)
  638. p += snprint(p, ep-p, "%s %d %d\n",
  639. batterystatus(apm.battery[i].status),
  640. apm.battery[i].percent, apm.battery[i].time);
  641. readstr(r, buf);
  642. respond(r, nil);
  643. }
  644. int
  645. iscmd(char *p, char *cmd)
  646. {
  647. int l;
  648. l = strlen(cmd);
  649. return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t';
  650. }
  651. char*
  652. skip(char *p, char *cmd)
  653. {
  654. p += strlen(cmd);
  655. while(*p==' ' || *p=='\t')
  656. p++;
  657. return p;
  658. }
  659. static void
  660. respondx(Req *r, int c)
  661. {
  662. char err[ERRMAX];
  663. if(c == 0)
  664. respond(r, nil);
  665. else{
  666. rerrstr(err, sizeof err);
  667. respond(r, err);
  668. }
  669. }
  670. /*
  671. * we don't do suspend because it messes up the
  672. * cycle counter as well as the pcmcia ethernet cards.
  673. */
  674. static void
  675. ctlwrite(Req *r)
  676. {
  677. char buf[80], *p, *q;
  678. int dev;
  679. long count;
  680. count = r->ifcall.count;
  681. if(count > sizeof(buf)-1)
  682. count = sizeof(buf)-1;
  683. memmove(buf, r->ifcall.data, count);
  684. buf[count] = '\0';
  685. if(count && buf[count-1] == '\n'){
  686. --count;
  687. buf[count] = '\0';
  688. }
  689. q = buf;
  690. p = strchr(q, ' ');
  691. if(p==nil)
  692. p = q+strlen(q);
  693. else
  694. *p++ = '\0';
  695. if(strcmp(q, "")==0 || strcmp(q, "system")==0)
  696. dev = DevAll;
  697. else if(strcmp(q, "display")==0)
  698. dev = DevDisplay;
  699. else if(strcmp(q, "storage")==0)
  700. dev = DevStorage;
  701. else if(strcmp(q, "lpt")==0)
  702. dev = DevLpt;
  703. else if(strcmp(q, "eia")==0)
  704. dev = DevEia;
  705. else if(strcmp(q, "network")==0)
  706. dev = DevNetwork;
  707. else if(strcmp(q, "pcmcia")==0)
  708. dev = DevPCMCIA;
  709. else{
  710. respond(r, "unknown device");
  711. return;
  712. }
  713. if(strcmp(p, "enable")==0)
  714. respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt));
  715. else if(strcmp(p, "disable")==0)
  716. respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt));
  717. else if(strcmp(p, "standby")==0)
  718. respondx(r, apmsetpowerstate(&apm, dev, PowerStandby));
  719. else if(strcmp(p, "on")==0)
  720. respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled));
  721. /*
  722. else if(strcmp(p, "off")==0)
  723. respondx(r, apmsetpowerstate(&apm, dev, PowerOff));
  724. */
  725. else if(strcmp(p, "suspend")==0)
  726. respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend));
  727. else
  728. respond(r, "unknown verb");
  729. }
  730. static int
  731. statusline(char *buf, int nbuf, char *name, int dev)
  732. {
  733. int s;
  734. char *state;
  735. state = "unknown";
  736. if((s = apmgetpowerstate(&apm, dev)) >= 0)
  737. state = powerstate(s);
  738. return snprint(buf, nbuf, "%s %s\n", name, state);
  739. }
  740. static void
  741. ctlread(Req *r)
  742. {
  743. char buf[256+7*50], *ep, *p;
  744. p = buf;
  745. ep = buf+sizeof buf;
  746. p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus));
  747. p += snprint(p, ep-p, "capabilities");
  748. if(apm.capabilities & CapStandby)
  749. p += snprint(p, ep-p, " standby");
  750. if(apm.capabilities & CapSuspend)
  751. p += snprint(p, ep-p, " suspend");
  752. if(apm.capabilities & CapSlowCpu)
  753. p += snprint(p, ep-p, " slowcpu");
  754. p += snprint(p, ep-p, "\n");
  755. p += statusline(p, ep-p, "system", DevAll);
  756. p += statusline(p, ep-p, "display", DevDisplay);
  757. p += statusline(p, ep-p, "storage", DevStorage);
  758. p += statusline(p, ep-p, "lpt", DevLpt);
  759. p += statusline(p, ep-p, "eia", DevEia|All);
  760. p += statusline(p, ep-p, "network", DevNetwork|All);
  761. p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All);
  762. USED(p);
  763. readstr(r, buf);
  764. respond(r, nil);
  765. }
  766. enum {
  767. STACK = 16384,
  768. };
  769. Channel *creq;
  770. Channel *cflush;
  771. Channel *cevent;
  772. Req *rlist, **tailp;
  773. int rp, wp;
  774. int nopoll;
  775. char eventq[32][80];
  776. static void
  777. flushthread(void*)
  778. {
  779. Req *r, *or, **rq;
  780. threadsetname("flushthread");
  781. while(r = recvp(cflush)){
  782. or = r->oldreq;
  783. for(rq=&rlist; *rq; rq=&(*rq)->aux){
  784. if(*rq == or){
  785. *rq = or->aux;
  786. if(tailp==&or->aux)
  787. tailp = rq;
  788. break;
  789. }
  790. }
  791. respond(r, nil);
  792. }
  793. }
  794. static void
  795. answerany(void)
  796. {
  797. char *buf;
  798. int l, m;
  799. Req *r;
  800. if(rlist==nil || rp==wp)
  801. return;
  802. while(rlist && rp != wp){
  803. r = rlist;
  804. rlist = r->aux;
  805. if(rlist==nil)
  806. tailp = &rlist;
  807. l = 0;
  808. buf = r->ofcall.data;
  809. m = r->ofcall.count;
  810. while(rp != wp){
  811. if(l+strlen(eventq[rp]) <= m){
  812. strcpy(buf+l, eventq[rp]);
  813. l += strlen(buf+l);
  814. }else if(l==0){
  815. strncpy(buf, eventq[rp], m-1);
  816. buf[m-1] = '\0';
  817. l += m;
  818. }else
  819. break;
  820. rp++;
  821. if(rp == nelem(eventq))
  822. rp = 0;
  823. }
  824. r->ofcall.count = l;
  825. respond(r, nil);
  826. }
  827. }
  828. static void
  829. eventwatch(void*)
  830. {
  831. int e, s;
  832. threadsetname("eventwatch");
  833. for(;;){
  834. s = 0;
  835. while((e = apmgetevent(&apm)) >= 0){
  836. sendul(cevent, e);
  837. s = 1;
  838. }
  839. if(s)
  840. sendul(cevent, -1);
  841. if(sleep(750) < 0)
  842. break;
  843. }
  844. }
  845. static void
  846. eventthread(void*)
  847. {
  848. int e;
  849. threadsetname("eventthread");
  850. for(;;){
  851. while((e = recvul(cevent)) >= 0){
  852. snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));
  853. strcat(eventq[wp], "\n");
  854. wp++;
  855. if(wp==nelem(eventq))
  856. wp = 0;
  857. if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))
  858. break;
  859. }
  860. answerany();
  861. }
  862. }
  863. static void
  864. eventproc(void*)
  865. {
  866. Req *r;
  867. threadsetname("eventproc");
  868. creq = chancreate(sizeof(Req*), 0);
  869. cevent = chancreate(sizeof(ulong), 0);
  870. cflush = chancreate(sizeof(Req*), 0);
  871. tailp = &rlist;
  872. if(!nopoll)
  873. proccreate(eventwatch, nil, STACK);
  874. threadcreate(eventthread, nil, STACK);
  875. threadcreate(flushthread, nil, STACK);
  876. while(r = recvp(creq)){
  877. *tailp = r;
  878. r->aux = nil;
  879. tailp = &r->aux;
  880. answerany();
  881. }
  882. }
  883. static void
  884. fsflush(Req *r)
  885. {
  886. sendp(cflush, r);
  887. }
  888. static void
  889. eventread(Req *r)
  890. {
  891. sendp(creq, r);
  892. }
  893. static void
  894. fsattach(Req *r)
  895. {
  896. char *spec;
  897. static int first = 1;
  898. spec = r->ifcall.aname;
  899. if(first){
  900. first = 0;
  901. proccreate(eventproc, nil, STACK);
  902. }
  903. if(spec && spec[0]){
  904. respond(r, "invalid attach specifier");
  905. return;
  906. }
  907. r->fid->qid = dfile[0].qid;
  908. r->ofcall.qid = dfile[0].qid;
  909. respond(r, nil);
  910. }
  911. Srv fs = {
  912. .attach= fsattach,
  913. .walk1= fswalk1,
  914. .open= fsopen,
  915. .read= fsread,
  916. .write= fswrite,
  917. .stat= fsstat,
  918. .flush= fsflush,
  919. };
  920. void
  921. usage(void)
  922. {
  923. fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");
  924. exits("usage");
  925. }
  926. void
  927. threadmain(int argc, char **argv)
  928. {
  929. char *dev, *mtpt, *srv;
  930. dev = nil;
  931. mtpt = "/mnt/apm";
  932. srv = nil;
  933. ARGBEGIN{
  934. case 'A':
  935. apmdebug = 1;
  936. break;
  937. case 'D':
  938. chatty9p = 1;
  939. break;
  940. case 'P':
  941. nopoll = 1;
  942. break;
  943. case 'd':
  944. dev = EARGF(usage());
  945. break;
  946. case 'i':
  947. fs.nopipe++;
  948. fs.infd = 0;
  949. fs.outfd = 1;
  950. mtpt = nil;
  951. break;
  952. case 'm':
  953. mtpt = EARGF(usage());
  954. break;
  955. case 's':
  956. srv = EARGF(usage());
  957. break;
  958. }ARGEND
  959. if(dev == nil){
  960. if((apm.fd = open("/dev/apm", ORDWR)) < 0
  961. && (apm.fd = open("#P/apm", ORDWR)) < 0){
  962. fprint(2, "open %s: %r\n", dev);
  963. threadexitsall("open");
  964. }
  965. } else if((apm.fd = open(dev, ORDWR)) < 0){
  966. fprint(2, "open %s: %r\n", dev);
  967. threadexitsall("open");
  968. }
  969. if(apmversion(&apm) < 0){
  970. fprint(2, "cannot get apm version: %r\n");
  971. threadexitsall("apmversion");
  972. }
  973. if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){
  974. fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);
  975. threadexitsall("apmversion");
  976. }
  977. if(apmgetcapabilities(&apm) < 0)
  978. fprint(2, "warning: cannot read apm capabilities: %r\n");
  979. apminstallationcheck(&apm);
  980. apmcpuidle(&apm);
  981. rfork(RFNOTEG);
  982. threadpostmountsrv(&fs, srv, mtpt, MREPL);
  983. }