apm.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  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 requested 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. respond(or, "interrupted");
  789. break;
  790. }
  791. }
  792. respond(r, nil);
  793. }
  794. }
  795. static void
  796. answerany(void)
  797. {
  798. char *buf;
  799. int l, m;
  800. Req *r;
  801. if(rlist==nil || rp==wp)
  802. return;
  803. while(rlist && rp != wp){
  804. r = rlist;
  805. rlist = r->aux;
  806. if(rlist==nil)
  807. tailp = &rlist;
  808. l = 0;
  809. buf = r->ofcall.data;
  810. m = r->ofcall.count;
  811. while(rp != wp){
  812. if(l+strlen(eventq[rp]) <= m){
  813. strcpy(buf+l, eventq[rp]);
  814. l += strlen(buf+l);
  815. }else if(l==0){
  816. strncpy(buf, eventq[rp], m-1);
  817. buf[m-1] = '\0';
  818. l += m;
  819. }else
  820. break;
  821. rp++;
  822. if(rp == nelem(eventq))
  823. rp = 0;
  824. }
  825. r->ofcall.count = l;
  826. respond(r, nil);
  827. }
  828. }
  829. static void
  830. eventwatch(void*)
  831. {
  832. int e, s;
  833. threadsetname("eventwatch");
  834. for(;;){
  835. s = 0;
  836. while((e = apmgetevent(&apm)) >= 0){
  837. sendul(cevent, e);
  838. s = 1;
  839. }
  840. if(s)
  841. sendul(cevent, -1);
  842. if(sleep(750) < 0)
  843. break;
  844. }
  845. }
  846. static void
  847. eventthread(void*)
  848. {
  849. int e;
  850. threadsetname("eventthread");
  851. for(;;){
  852. while((e = recvul(cevent)) >= 0){
  853. snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));
  854. strcat(eventq[wp], "\n");
  855. wp++;
  856. if(wp==nelem(eventq))
  857. wp = 0;
  858. if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))
  859. break;
  860. }
  861. answerany();
  862. }
  863. }
  864. static void
  865. eventproc(void*)
  866. {
  867. Req *r;
  868. threadsetname("eventproc");
  869. creq = chancreate(sizeof(Req*), 0);
  870. cevent = chancreate(sizeof(ulong), 0);
  871. cflush = chancreate(sizeof(Req*), 0);
  872. tailp = &rlist;
  873. if(!nopoll)
  874. proccreate(eventwatch, nil, STACK);
  875. threadcreate(eventthread, nil, STACK);
  876. threadcreate(flushthread, nil, STACK);
  877. while(r = recvp(creq)){
  878. *tailp = r;
  879. r->aux = nil;
  880. tailp = &r->aux;
  881. answerany();
  882. }
  883. }
  884. static void
  885. fsflush(Req *r)
  886. {
  887. sendp(cflush, r);
  888. }
  889. static void
  890. eventread(Req *r)
  891. {
  892. sendp(creq, r);
  893. }
  894. static void
  895. fsattach(Req *r)
  896. {
  897. char *spec;
  898. static int first = 1;
  899. spec = r->ifcall.aname;
  900. if(first){
  901. first = 0;
  902. proccreate(eventproc, nil, STACK);
  903. }
  904. if(spec && spec[0]){
  905. respond(r, "invalid attach specifier");
  906. return;
  907. }
  908. r->fid->qid = dfile[0].qid;
  909. r->ofcall.qid = dfile[0].qid;
  910. respond(r, nil);
  911. }
  912. Srv fs = {
  913. .attach= fsattach,
  914. .walk1= fswalk1,
  915. .open= fsopen,
  916. .read= fsread,
  917. .write= fswrite,
  918. .stat= fsstat,
  919. .flush= fsflush,
  920. };
  921. void
  922. usage(void)
  923. {
  924. fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");
  925. exits("usage");
  926. }
  927. void
  928. threadmain(int argc, char **argv)
  929. {
  930. char *dev, *mtpt, *srv;
  931. dev = nil;
  932. mtpt = "/mnt/apm";
  933. srv = nil;
  934. ARGBEGIN{
  935. case 'A':
  936. apmdebug = 1;
  937. break;
  938. case 'D':
  939. chatty9p = 1;
  940. break;
  941. case 'P':
  942. nopoll = 1;
  943. break;
  944. case 'd':
  945. dev = EARGF(usage());
  946. break;
  947. case 'i':
  948. fs.nopipe++;
  949. fs.infd = 0;
  950. fs.outfd = 1;
  951. mtpt = nil;
  952. break;
  953. case 'm':
  954. mtpt = EARGF(usage());
  955. break;
  956. case 's':
  957. srv = EARGF(usage());
  958. break;
  959. }ARGEND
  960. if(dev == nil){
  961. if((apm.fd = open("/dev/apm", ORDWR)) < 0
  962. && (apm.fd = open("#P/apm", ORDWR)) < 0){
  963. fprint(2, "open %s: %r\n", dev);
  964. threadexitsall("open");
  965. }
  966. } else if((apm.fd = open(dev, ORDWR)) < 0){
  967. fprint(2, "open %s: %r\n", dev);
  968. threadexitsall("open");
  969. }
  970. if(apmversion(&apm) < 0){
  971. fprint(2, "cannot get apm version: %r\n");
  972. threadexitsall("apmversion");
  973. }
  974. if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){
  975. fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);
  976. threadexitsall("apmversion");
  977. }
  978. if(apmgetcapabilities(&apm) < 0)
  979. fprint(2, "warning: cannot read apm capabilities: %r\n");
  980. apminstallationcheck(&apm);
  981. apmcpuidle(&apm);
  982. rfork(RFNOTEG);
  983. threadpostmountsrv(&fs, srv, mtpt, MREPL);
  984. }