UPS: apcupsd clean sources
[tomato.git] / release / src / router / apcupsd / src / device.c
blobfff1799d1ed00cdcba46d37e52db7dea2575255d
1 /*
2 * apcdevice.c
4 * Generic device handling
6 * Written by Riccardo Fachetti 2000 from Kern's design
7 */
9 /*
10 * Copyright (C) 2000-2004 Kern Sibbald
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of version 2 of the GNU General
14 * Public License as published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public
22 * License along with this program; if not, write to the Free
23 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 * MA 02111-1307, USA.
27 /*
28 * This is a sort of helper routine between apcupsd core and the drivers.
29 * The raw calls into the drivers are through function pointers in the
30 * ups device structure, and are #defined to the following:
32 * device_open(ups)
33 * device_setup(ups)
34 * device_close(ups)
35 * device_kill_power(ups)
36 * device_shutdown(ups)
37 * device_read_static_data(ups)
38 * device_read_volatile_data(ups)
39 * device_get_capabilities(ups)
40 * device_check_state(ups)
41 * device_program_eeprom(ups)
42 * device_entry_point(ups, command, data)
44 * see include/apc_drivers.h for more details on each routine.
47 #include "apc.h"
49 /* Forward referenced function */
50 static int device_wait_time(UPSINFO *ups);
52 /*********************************************************************/
53 void setup_device(UPSINFO *ups)
56 * Marko Sakari Asplund <Marko.Asplund@cern.ch>
57 * prevents double init of UPS device 9/25/98
59 if (ups->is_dev_setup())
60 return;
62 ups->set_dev_setup();
64 device_open(ups);
66 /* If create_lockfile fails there's no need to delete_lockfile. */
67 if ((ups->fd != -1) && create_lockfile(ups) == LCKERROR) {
68 device_close(ups);
69 Error_abort0("Unable to create UPS lock file.\n"
70 " If apcupsd or apctest is already running,\n"
71 " please stop it and run this program again.\n");
74 device_setup(ups);
75 device_get_capabilities(ups);
78 /*********************************************************************/
79 void initiate_hibernate(UPSINFO *ups)
81 FILE *pwdf;
82 int killcount;
84 if (ups->mode.type == DUMB_UPS) {
85 /* Make sure we are on battery */
86 for (killcount = 0; killcount < 3; killcount++)
87 device_read_volatile_data(ups);
91 * ****FIXME***** This big if is BROKEN in the
92 * case that there is no real power failure.
94 * We really need to find out if we are on batteries
95 * and if not, delete the PWRFAIL file. Note, the code
96 * above only tests UPS_onbatt flag for dumb UPSes.
99 pwdf = fopen(ups->pwrfailpath, "r");
100 if ((pwdf == NULL && ups->mode.type != DUMB_UPS) ||
101 (pwdf == NULL && ups->is_onbatt() && ups->mode.type == DUMB_UPS)) {
104 * At this point, we really should not be attempting
105 * a kill power since either the powerfail file is
106 * not defined, or we are not on batteries.
109 /* Now complain */
110 log_event(ups, LOG_WARNING,
111 "Cannot find %s file.\n Killpower requested in "
112 "non-power fail condition or bug.\n Killpower request "
113 "ignored at %s:%d\n", ups->pwrfailpath, __FILE__, __LINE__);
114 Error_abort3(
115 "Cannot find %s file.\n Killpower requested in "
116 "non-power fail condition or bug.\n Killpower request "
117 "ignored at %s:%d\n", ups->pwrfailpath, __FILE__, __LINE__);
118 } else {
119 /* We are on batteries, so do the kill_power */
120 if (ups->upsclass.type == SHAREMASTER) {
121 log_event(ups, LOG_WARNING,
122 "Waiting 30 seconds for slave(s) to shutdown.");
123 sleep(30);
126 /* close the powerfail file */
127 if (pwdf)
128 fclose(pwdf);
130 log_event(ups, LOG_WARNING, "Attempting to kill the UPS power!");
132 if (ups->upsclass.type == SHARESLAVE) {
133 sleep(10);
134 log_event(ups, LOG_WARNING, "Waiting For ShareUPS Master to shutdown");
135 sleep(60);
136 log_event(ups, LOG_WARNING, "Failed to have power killed by Master!");
139 * ***FIXME*** this really should not do a reboot here,
140 * but rather a halt or nothing -- KES
142 /* generate_event(ups, CMDDOREBOOT); */
144 log_event(ups, LOG_WARNING, "Perform CPU-reset or power-off");
145 return;
146 } else {
147 /* it must be a SmartUPS or BackUPS */
148 device_kill_power(ups);
153 /*********************************************************************/
154 void initiate_shutdown(UPSINFO *ups)
156 log_event(ups, LOG_WARNING, "Attempting to shutdown the UPS!");
157 device_shutdown(ups);
161 * After the device is initialized, we come here
162 * to read all the information we can about the UPS.
164 void prep_device(UPSINFO *ups)
166 device_read_static_data(ups);
168 /* If no UPS name found, use hostname, or "default" */
169 if (ups->upsname[0] == 0) { /* no name given */
170 gethostname(ups->upsname, sizeof(ups->upsname) - 1);
171 if (ups->upsname[0] == 0) /* error */
172 astrncpy(ups->upsname, "default", sizeof(ups->upsname));
176 /* Called once every 5 seconds to read all UPS info */
177 int fillUPS(UPSINFO *ups)
179 device_read_volatile_data(ups);
181 return 0;
184 /* NOTE! This is the starting point for a separate process (thread). */
185 void do_device(UPSINFO *ups)
187 /* get all data so apcaccess is happy */
188 fillUPS(ups);
190 while(1)
192 /* compute appropriate wait time */
193 ups->wait_time = device_wait_time(ups);
195 Dmsg2(70, "Before do_action: 0x%x (OB:%d).\n",
196 ups->Status, ups->is_onbatt());
198 /* take event actions */
199 do_action(ups);
201 Dmsg2(70, "Before fillUPS: 0x%x (OB:%d).\n",
202 ups->Status, ups->is_onbatt());
204 /* Get all info available from UPS by asking it questions */
205 fillUPS(ups);
207 Dmsg2(70, "Before do_action: 0x%x (OB:%d).\n",
208 ups->Status, ups->is_onbatt());
210 /* take event actions */
211 do_action(ups);
213 Dmsg2(70, "Before do_reports: 0x%x (OB:%d).\n",
214 ups->Status, ups->is_onbatt());
216 do_reports(ups);
218 /* compute appropriate wait time */
219 ups->wait_time = device_wait_time(ups);
221 Dmsg2(70, "Before device_check_state: 0x%x (OB:%d).\n",
222 ups->Status, ups->is_onbatt());
225 * Check the UPS to see if has changed state.
226 * This routine waits a reasonable time to prevent
227 * consuming too much CPU time.
229 device_check_state(ups);
234 * Each device handler when called at device_check_state() waits
235 * a specified time for the next event. In general, we want this
236 * to be as long as possible (i.e. about a minute) to prevent
237 * excessive "polling" because when device_check_state() returns,
238 * repoll the UPS (fillUPS).
239 * This routine attempts to determine a reasonable "sleep" time
240 * for the device.
242 static int device_wait_time(UPSINFO *ups)
244 int wait_time;
246 if (ups->is_fastpoll() || !ups->is_battpresent())
247 wait_time = TIMER_FAST;
248 else if (ups->is_commlost())
249 wait_time = TIMER_FAST*5;
250 else
251 wait_time = ups->polltime; /* normally 60 seconds */
253 /* Make sure we do data and stats when asked */
254 if (ups->datatime && ups->datatime < wait_time)
255 wait_time = ups->datatime;
257 if (ups->stattime && ups->stattime < wait_time)
258 wait_time = ups->stattime;
260 /* Sanity check */
261 if (wait_time < TIMER_FAST)
262 wait_time = TIMER_FAST;
264 return wait_time;