apm.c 20 KB

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