4 * Functions to open/setup/close the device
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,
31 * This is the first routine called in the driver, and it is only
34 int dumb_ups_open(UPSINFO
*ups
)
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.");
45 memset(my_data
, 0, sizeof(SIMPLE_DATA
));
46 ups
->driver_internal_data
= my_data
;
48 log_event(ups
, LOG_ERR
,
49 "apcsmart_ups_open called twice. This shouldn't happen.");
52 char *opendev
= ups
->device
;
55 // On Win32 add \\.\ UNC prefix to COMx in order to correctly address
57 char device
[MAXSTRING
];
58 if (!strnicmp(ups
->device
, "COM", 3)) {
59 snprintf(device
, sizeof(device
), "\\\\.\\%s", ups
->device
);
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
);
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
) {
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
);
138 case APC_940_0020B
: /* clear killpwr_bit */
140 (void)ioctl(ups
->fd
, TIOCMBIC
, &dtr_bit
);
141 (void)ioctl(ups
->fd
, TIOCMBIC
, &dtr_bit
);
142 (void)ioctl(ups
->fd
, TIOCMBIC
, &dtr_bit
);
152 free(ups
->driver_internal_data
);
153 ups
->driver_internal_data
= NULL
;
158 int dumb_ups_setup(UPSINFO
*ups
)
162 switch (ups
->cable
.type
) {
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
);
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
);
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
);