apm.c 20 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  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(uvlong 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;
  606. uvlong offset;
  607. char *p, *ep;
  608. Dir d;
  609. if(r->ifcall.offset == 0)
  610. offset = 0;
  611. else
  612. offset = (uvlong)r->fid->aux;
  613. p = r->ofcall.data;
  614. ep = r->ofcall.data+r->ifcall.count;
  615. if(offset == 0) /* skip root */
  616. offset = 1;
  617. for(; p+2 < ep; p+=n){
  618. if(fillstat(offset, &d, 0) < 0)
  619. break;
  620. n = convD2M(&d, (uchar*)p, ep-p);
  621. if(n <= BIT16SZ)
  622. break;
  623. offset++;
  624. }
  625. r->fid->aux = (void*)offset;
  626. r->ofcall.count = p - r->ofcall.data;
  627. respond(r, nil);
  628. }
  629. static void
  630. batteryread(Req *r)
  631. {
  632. char buf[Mbattery*80], *ep, *p;
  633. int i;
  634. apmgetpowerstatus(&apm, DevAll);
  635. p = buf;
  636. ep = buf+sizeof buf;
  637. *p = '\0'; /* could be no batteries */
  638. for(i=0; i<apm.nbattery && i<Mbattery; i++)
  639. p += snprint(p, ep-p, "%s %d %d\n",
  640. batterystatus(apm.battery[i].status),
  641. apm.battery[i].percent, apm.battery[i].time);
  642. readstr(r, buf);
  643. respond(r, nil);
  644. }
  645. int
  646. iscmd(char *p, char *cmd)
  647. {
  648. int l;
  649. l = strlen(cmd);
  650. return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t';
  651. }
  652. char*
  653. skip(char *p, char *cmd)
  654. {
  655. p += strlen(cmd);
  656. while(*p==' ' || *p=='\t')
  657. p++;
  658. return p;
  659. }
  660. static void
  661. respondx(Req *r, int c)
  662. {
  663. char err[ERRMAX];
  664. if(c == 0)
  665. respond(r, nil);
  666. else{
  667. rerrstr(err, sizeof err);
  668. respond(r, err);
  669. }
  670. }
  671. /*
  672. * we don't do suspend because it messes up the
  673. * cycle counter as well as the pcmcia ethernet cards.
  674. */
  675. static void
  676. ctlwrite(Req *r)
  677. {
  678. char buf[80], *p, *q;
  679. int dev;
  680. long count;
  681. count = r->ifcall.count;
  682. if(count > sizeof(buf)-1)
  683. count = sizeof(buf)-1;
  684. memmove(buf, r->ifcall.data, count);
  685. buf[count] = '\0';
  686. if(count && buf[count-1] == '\n'){
  687. --count;
  688. buf[count] = '\0';
  689. }
  690. q = buf;
  691. p = strchr(q, ' ');
  692. if(p==nil)
  693. p = q+strlen(q);
  694. else
  695. *p++ = '\0';
  696. if(strcmp(q, "")==0 || strcmp(q, "system")==0)
  697. dev = DevAll;
  698. else if(strcmp(q, "display")==0)
  699. dev = DevDisplay;
  700. else if(strcmp(q, "storage")==0)
  701. dev = DevStorage;
  702. else if(strcmp(q, "lpt")==0)
  703. dev = DevLpt;
  704. else if(strcmp(q, "eia")==0)
  705. dev = DevEia;
  706. else if(strcmp(q, "network")==0)
  707. dev = DevNetwork;
  708. else if(strcmp(q, "pcmcia")==0)
  709. dev = DevPCMCIA;
  710. else{
  711. respond(r, "unknown device");
  712. return;
  713. }
  714. if(strcmp(p, "enable")==0)
  715. respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt));
  716. else if(strcmp(p, "disable")==0)
  717. respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt));
  718. else if(strcmp(p, "standby")==0)
  719. respondx(r, apmsetpowerstate(&apm, dev, PowerStandby));
  720. else if(strcmp(p, "on")==0)
  721. respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled));
  722. /*
  723. else if(strcmp(p, "off")==0)
  724. respondx(r, apmsetpowerstate(&apm, dev, PowerOff));
  725. */
  726. else if(strcmp(p, "suspend")==0)
  727. respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend));
  728. else
  729. respond(r, "unknown verb");
  730. }
  731. static int
  732. statusline(char *buf, int nbuf, char *name, int dev)
  733. {
  734. int s;
  735. char *state;
  736. state = "unknown";
  737. if((s = apmgetpowerstate(&apm, dev)) >= 0)
  738. state = powerstate(s);
  739. return snprint(buf, nbuf, "%s %s\n", name, state);
  740. }
  741. static void
  742. ctlread(Req *r)
  743. {
  744. char buf[256+7*50], *ep, *p;
  745. p = buf;
  746. ep = buf+sizeof buf;
  747. p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus));
  748. p += snprint(p, ep-p, "capabilities");
  749. if(apm.capabilities & CapStandby)
  750. p += snprint(p, ep-p, " standby");
  751. if(apm.capabilities & CapSuspend)
  752. p += snprint(p, ep-p, " suspend");
  753. if(apm.capabilities & CapSlowCpu)
  754. p += snprint(p, ep-p, " slowcpu");
  755. p += snprint(p, ep-p, "\n");
  756. p += statusline(p, ep-p, "system", DevAll);
  757. p += statusline(p, ep-p, "display", DevDisplay);
  758. p += statusline(p, ep-p, "storage", DevStorage);
  759. p += statusline(p, ep-p, "lpt", DevLpt);
  760. p += statusline(p, ep-p, "eia", DevEia|All);
  761. p += statusline(p, ep-p, "network", DevNetwork|All);
  762. p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All);
  763. USED(p);
  764. readstr(r, buf);
  765. respond(r, nil);
  766. }
  767. enum {
  768. STACK = 16384,
  769. };
  770. Channel *creq;
  771. Channel *cflush;
  772. Channel *cevent;
  773. Req *rlist, **tailp;
  774. int rp, wp;
  775. int nopoll;
  776. char eventq[32][80];
  777. static void
  778. flushthread(void*)
  779. {
  780. Req *r, *or, **rq;
  781. threadsetname("flushthread");
  782. while(r = recvp(cflush)){
  783. or = r->oldreq;
  784. for(rq=&rlist; *rq; rq=&(*rq)->aux){
  785. if(*rq == or){
  786. *rq = or->aux;
  787. if(tailp==&or->aux)
  788. tailp = rq;
  789. respond(or, "interrupted");
  790. break;
  791. }
  792. }
  793. respond(r, nil);
  794. }
  795. }
  796. static void
  797. answerany(void)
  798. {
  799. char *buf;
  800. int l, m;
  801. Req *r;
  802. if(rlist==nil || rp==wp)
  803. return;
  804. while(rlist && rp != wp){
  805. r = rlist;
  806. rlist = r->aux;
  807. if(rlist==nil)
  808. tailp = &rlist;
  809. l = 0;
  810. buf = r->ofcall.data;
  811. m = r->ifcall.count;
  812. while(rp != wp){
  813. if(l+strlen(eventq[rp]) <= m){
  814. strcpy(buf+l, eventq[rp]);
  815. l += strlen(buf+l);
  816. }else if(l==0){
  817. strncpy(buf, eventq[rp], m-1);
  818. buf[m-1] = '\0';
  819. l += m;
  820. }else
  821. break;
  822. rp++;
  823. if(rp == nelem(eventq))
  824. rp = 0;
  825. }
  826. r->ofcall.count = l;
  827. respond(r, nil);
  828. }
  829. }
  830. static void
  831. eventwatch(void*)
  832. {
  833. int e, s;
  834. threadsetname("eventwatch");
  835. for(;;){
  836. s = 0;
  837. while((e = apmgetevent(&apm)) >= 0){
  838. sendul(cevent, e);
  839. s = 1;
  840. }
  841. if(s)
  842. sendul(cevent, -1);
  843. if(sleep(750) < 0)
  844. break;
  845. }
  846. }
  847. static void
  848. eventthread(void*)
  849. {
  850. int e;
  851. threadsetname("eventthread");
  852. for(;;){
  853. while((e = recvul(cevent)) >= 0){
  854. snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));
  855. strcat(eventq[wp], "\n");
  856. wp++;
  857. if(wp==nelem(eventq))
  858. wp = 0;
  859. if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))
  860. break;
  861. }
  862. answerany();
  863. }
  864. }
  865. static void
  866. eventproc(void*)
  867. {
  868. Req *r;
  869. threadsetname("eventproc");
  870. creq = chancreate(sizeof(Req*), 0);
  871. cevent = chancreate(sizeof(ulong), 0);
  872. cflush = chancreate(sizeof(Req*), 0);
  873. tailp = &rlist;
  874. if(!nopoll)
  875. proccreate(eventwatch, nil, STACK);
  876. threadcreate(eventthread, nil, STACK);
  877. threadcreate(flushthread, nil, STACK);
  878. while(r = recvp(creq)){
  879. *tailp = r;
  880. r->aux = nil;
  881. tailp = &r->aux;
  882. answerany();
  883. }
  884. }
  885. static void
  886. fsflush(Req *r)
  887. {
  888. sendp(cflush, r);
  889. }
  890. static void
  891. eventread(Req *r)
  892. {
  893. sendp(creq, r);
  894. }
  895. static void
  896. fsattach(Req *r)
  897. {
  898. char *spec;
  899. static int first = 1;
  900. spec = r->ifcall.aname;
  901. if(first){
  902. first = 0;
  903. proccreate(eventproc, nil, STACK);
  904. }
  905. if(spec && spec[0]){
  906. respond(r, "invalid attach specifier");
  907. return;
  908. }
  909. r->fid->qid = dfile[0].qid;
  910. r->ofcall.qid = dfile[0].qid;
  911. respond(r, nil);
  912. }
  913. Srv fs = {
  914. .attach= fsattach,
  915. .walk1= fswalk1,
  916. .open= fsopen,
  917. .read= fsread,
  918. .write= fswrite,
  919. .stat= fsstat,
  920. .flush= fsflush,
  921. };
  922. void
  923. usage(void)
  924. {
  925. fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");
  926. exits("usage");
  927. }
  928. void
  929. threadmain(int argc, char **argv)
  930. {
  931. char *dev, *mtpt, *srv;
  932. dev = nil;
  933. mtpt = "/mnt/apm";
  934. srv = nil;
  935. ARGBEGIN{
  936. case 'A':
  937. apmdebug = 1;
  938. break;
  939. case 'D':
  940. chatty9p = 1;
  941. break;
  942. case 'P':
  943. nopoll = 1;
  944. break;
  945. case 'd':
  946. dev = EARGF(usage());
  947. break;
  948. case 'i':
  949. fs.nopipe++;
  950. fs.infd = 0;
  951. fs.outfd = 1;
  952. mtpt = nil;
  953. break;
  954. case 'm':
  955. mtpt = EARGF(usage());
  956. break;
  957. case 's':
  958. srv = EARGF(usage());
  959. break;
  960. }ARGEND
  961. if(dev == nil){
  962. if((apm.fd = open("/dev/apm", ORDWR)) < 0
  963. && (apm.fd = open("#P/apm", ORDWR)) < 0){
  964. fprint(2, "open %s: %r\n", dev);
  965. threadexitsall("open");
  966. }
  967. } else if((apm.fd = open(dev, ORDWR)) < 0){
  968. fprint(2, "open %s: %r\n", dev);
  969. threadexitsall("open");
  970. }
  971. if(apmversion(&apm) < 0){
  972. fprint(2, "cannot get apm version: %r\n");
  973. threadexitsall("apmversion");
  974. }
  975. if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){
  976. fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);
  977. threadexitsall("apmversion");
  978. }
  979. if(apmgetcapabilities(&apm) < 0)
  980. fprint(2, "warning: cannot read apm capabilities: %r\n");
  981. apminstallationcheck(&apm);
  982. apmcpuidle(&apm);
  983. rfork(RFNOTEG);
  984. threadpostmountsrv(&fs, srv, mtpt, MREPL);
  985. }