UPS: apcupsd clean sources
[tomato.git] / release / src / router / apcupsd / src / drivers / dumb / dumbsetup.c
blob0c573ecd22f8bbc1ce7ba71c73a052754f4fd568
1 /*
2 * dumbsetup.c
4 * Functions to open/setup/close the device
5 */
7 /*
8 * Copyright (C) 1999-2001 Riccardo Facchetti <riccardo@apcupsd.org>
9 * Copyright (C) 1996-99 Andre M. Hedrick <andre@suse.com>
10 * Copyright (C) 1999-2001 Riccardo Facchetti <riccardo@apcupsd.org>
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 #include "apc.h"
28 #include "dumb.h"
31 * This is the first routine called in the driver, and it is only
32 * called once.
34 int dumb_ups_open(UPSINFO *ups)
36 int cmd;
37 SIMPLE_DATA *my_data = (SIMPLE_DATA *) ups->driver_internal_data;
39 if (my_data == NULL) {
40 my_data = (SIMPLE_DATA *) malloc(sizeof(SIMPLE_DATA));
41 if (my_data == NULL) {
42 log_event(ups, LOG_ERR, "Out of memory.");
43 exit(1);
45 memset(my_data, 0, sizeof(SIMPLE_DATA));
46 ups->driver_internal_data = my_data;
47 } else {
48 log_event(ups, LOG_ERR,
49 "apcsmart_ups_open called twice. This shouldn't happen.");
52 char *opendev = ups->device;
54 #ifdef HAVE_MINGW
55 // On Win32 add \\.\ UNC prefix to COMx in order to correctly address
56 // ports >= COM10.
57 char device[MAXSTRING];
58 if (!strnicmp(ups->device, "COM", 3)) {
59 snprintf(device, sizeof(device), "\\\\.\\%s", ups->device);
60 opendev = device;
62 #endif
64 if ((ups->fd = open(opendev, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
65 Error_abort2("Cannot open UPS port %s: %s\n", opendev, strerror(errno));
67 /* Cancel the no delay we just set */
68 cmd = fcntl(ups->fd, F_GETFL, 0);
69 fcntl(ups->fd, F_SETFL, cmd & ~O_NDELAY);
71 /* Save old settings */
72 tcgetattr(ups->fd, &my_data->oldtio);
74 my_data->newtio.c_cflag = DEFAULT_SPEED | CS8 | CLOCAL | CREAD;
75 my_data->newtio.c_iflag = IGNPAR; /* Ignore errors, raw input */
76 my_data->newtio.c_oflag = 0; /* Raw output */
77 my_data->newtio.c_lflag = 0; /* No local echo */
79 #if defined(HAVE_OPENBSD_OS) || \
80 defined(HAVE_FREEBSD_OS) || \
81 defined(HAVE_NETBSD_OS)
82 my_data->newtio.c_ispeed = DEFAULT_SPEED; /* Set input speed */
83 my_data->newtio.c_ospeed = DEFAULT_SPEED; /* Set output speed */
84 #endif /* __openbsd__ || __freebsd__ || __netbsd__ */
86 /* This makes a non.blocking read() with TIMER_READ (10) sec. timeout */
87 my_data->newtio.c_cc[VMIN] = 0;
88 my_data->newtio.c_cc[VTIME] = TIMER_READ * 10;
90 #if defined(HAVE_OSF1_OS) || defined(HAVE_LINUX_OS)
91 (void)cfsetospeed(&my_data->newtio, DEFAULT_SPEED);
92 (void)cfsetispeed(&my_data->newtio, DEFAULT_SPEED);
93 #endif /* do it the POSIX way */
95 tcflush(ups->fd, TCIFLUSH);
96 tcsetattr(ups->fd, TCSANOW, &my_data->newtio);
97 tcflush(ups->fd, TCIFLUSH);
99 ups->clear_slave();
101 return 1;
105 * This is the last routine called in the driver
107 int dumb_ups_close(UPSINFO *ups)
109 int rts_bit = TIOCM_RTS;
110 int st_bit = TIOCM_ST;
111 int dtr_bit = TIOCM_DTR;
114 * Do NOT reset the old values here as it causes the kill
115 * power to trigger on some systems.
117 * On the other hand do clear any kill_power bit previously
118 * set so that it doesn't remain set in the serial port and
119 * trigger a problem later.
121 * Note, we assume that the previous code has done a
122 * sleep() for at least 5 seconds.
125 switch (ups->cable.type) {
126 case CUSTOM_SIMPLE:
127 case APC_940_0095A:
128 case APC_940_0095B:
129 case APC_940_0095C: /* clear killpwr_bit */
130 (void)ioctl(ups->fd, TIOCMBIC, &rts_bit);
131 (void)ioctl(ups->fd, TIOCMBIC, &rts_bit);
132 (void)ioctl(ups->fd, TIOCMBIC, &st_bit);
133 break;
135 case APC_940_0119A:
136 case APC_940_0127A:
137 case APC_940_0128A:
138 case APC_940_0020B: /* clear killpwr_bit */
139 case APC_940_0020C:
140 (void)ioctl(ups->fd, TIOCMBIC, &dtr_bit);
141 (void)ioctl(ups->fd, TIOCMBIC, &dtr_bit);
142 (void)ioctl(ups->fd, TIOCMBIC, &dtr_bit);
143 break;
145 default:
146 break;
149 close(ups->fd);
150 ups->fd = -1;
152 free(ups->driver_internal_data);
153 ups->driver_internal_data = NULL;
155 return 1;
158 int dumb_ups_setup(UPSINFO *ups)
160 int serial_bits = 0;
162 switch (ups->cable.type) {
163 case CUSTOM_SIMPLE:
164 /* Clear killpwr bits */
165 serial_bits = TIOCM_RTS;
166 (void)ioctl(ups->fd, TIOCMBIC, &serial_bits);
168 /* Set bit for detecting Low Battery */
169 serial_bits = TIOCM_DTR;
170 (void)ioctl(ups->fd, TIOCMBIS, &serial_bits);
171 break;
173 case APC_940_0119A:
174 case APC_940_0127A:
175 case APC_940_0128A:
176 case APC_940_0020B:
177 case APC_940_0020C:
178 case MAM_CABLE: /* DTR=>enable CD & CTS RTS=>killpower */
179 /* Clear DTR bit (shutdown) and set RTS bit (tell we are ready) */
180 serial_bits = TIOCM_DTR;
181 (void)ioctl(ups->fd, TIOCMBIC, &serial_bits);
182 serial_bits = TIOCM_RTS;
183 (void)ioctl(ups->fd, TIOCMBIS, &serial_bits);
184 break;
186 case APC_940_0095A:
187 case APC_940_0095B:
188 case APC_940_0095C:
189 /* Have to clear RTS line to access the serial cable mode PnP */
190 serial_bits = TIOCM_RTS;
191 (void)ioctl(ups->fd, TIOCMBIC, &serial_bits);
193 /* Clear killpwr, lowbatt and again killpwr bits. */
194 serial_bits = TIOCM_RTS | TIOCM_CD;
195 (void)ioctl(ups->fd, TIOCMBIC, &serial_bits);
196 serial_bits = TIOCM_RTS;
197 (void)ioctl(ups->fd, TIOCMBIC, &serial_bits);
198 break;
200 default:
201 break;
204 return 1;