4 * Generic device handling
6 * Written by Riccardo Fachetti 2000 from Kern's design
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,
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:
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.
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())
66 /* If create_lockfile fails there's no need to delete_lockfile. */
67 if ((ups
->fd
!= -1) && create_lockfile(ups
) == LCKERROR
) {
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");
75 device_get_capabilities(ups
);
78 /*********************************************************************/
79 void initiate_hibernate(UPSINFO
*ups
)
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.
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__
);
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__
);
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.");
126 /* close the powerfail file */
130 log_event(ups
, LOG_WARNING
, "Attempting to kill the UPS power!");
132 if (ups
->upsclass
.type
== SHARESLAVE
) {
134 log_event(ups
, LOG_WARNING
, "Waiting For ShareUPS Master to shutdown");
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");
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
);
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 */
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 */
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 */
207 Dmsg2(70, "Before do_action: 0x%x (OB:%d).\n",
208 ups
->Status
, ups
->is_onbatt());
210 /* take event actions */
213 Dmsg2(70, "Before do_reports: 0x%x (OB:%d).\n",
214 ups
->Status
, ups
->is_onbatt());
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
242 static int device_wait_time(UPSINFO
*ups
)
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;
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
;
261 if (wait_time
< TIMER_FAST
)
262 wait_time
= TIMER_FAST
;