1 /*!
2  * @file libshut.c
3  * @brief HID Library - SHUT communication sub driver
4  *
5  * @author Copyright (C)
6  *  2006 - 2009 Arnaud Quette <aquette.dev@gmail.com>
7  *
8  *      This program is free software; you can redistribute it and/or modify
9  *      it under the terms of the GNU General Public License as published by
10  *      the Free Software Foundation; either version 2 of the License, or
11  *      (at your option) any later version.
12  *
13  *      This program is distributed in the hope that it will be useful,
14  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *      GNU General Public License for more details.
17  *
18  *      You should have received a copy of the GNU General Public License
19  *      along with this program; if not, write to the Free Software
20  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * -------------------------------------------------------------------------- */
23 
24 /* TODO list
25  * - cleanup, cleanup, cleanup
26  * - manage interrupt and complete libshut_get_interrupt / shut_control_msg routing
27  * - baudrate negotiation
28  * - complete shut_strerror
29  * - validate / complete commands and data table in mge-hid from mge-shut
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <string.h>
36 
37 #include "nut_stdint.h" /* for uint8_t, uint16_t, uint32_t */
38 
39 #include "serial.h"
40 #include "libshut.h"
41 #include "common.h" /* for xmalloc, upsdebugx prototypes */
42 
43 #define SHUT_DRIVER_NAME	"SHUT communication driver"
44 #define SHUT_DRIVER_VERSION	"0.85"
45 
46 /* communication driver description structure */
47 upsdrv_info_t comm_upsdrv_info = {
48 	SHUT_DRIVER_NAME,
49 	SHUT_DRIVER_VERSION,
50 	NULL,
51 	0,
52 	{ NULL }
53 };
54 
55 #define MAX_TRY 4
56 #define MAX_STRING_SIZE 128
57 
58 /*!
59  * HID descriptor, completed with desc{type,len}
60  */
61 struct my_hid_descriptor {
62         uint8_t  bLength;
63         uint8_t  bDescriptorType;
64         uint16_t bcdHID;
65         uint8_t  bCountryCode;
66         uint8_t  bNumDescriptors;
67         uint8_t  bReportDescriptorType;
68         uint16_t wDescriptorLength;
69 };
70 
71 /*!********************************************************
72  * USB spec information, synchronised with (ripped from) libusb
73  */
74 
75 /*
76  * Device and/or Interface Class codes
77  */
78 #define USB_CLASS_PER_INTERFACE		0	/* for DeviceClass */
79 #define USB_CLASS_AUDIO			1
80 #define USB_CLASS_COMM			2
81 #define USB_CLASS_HID			3
82 #define USB_CLASS_PRINTER		7
83 #define USB_CLASS_MASS_STORAGE		8
84 #define USB_CLASS_HUB			9
85 #define USB_CLASS_DATA			10
86 #define USB_CLASS_VENDOR_SPEC		0xff
87 
88 /*
89  * Descriptor types
90  */
91 #define USB_DT_DEVICE			0x01
92 #define USB_DT_CONFIG			0x02
93 #define USB_DT_STRING			0x03
94 #define USB_DT_INTERFACE		0x04
95 #define USB_DT_ENDPOINT			0x05
96 
97 #define USB_DT_HID			0x21
98 #define USB_DT_REPORT			0x22
99 #define USB_DT_PHYSICAL			0x23
100 #define USB_DT_HUB			0x29
101 
102 /*
103  * Descriptor sizes per descriptor type
104  */
105 #define USB_DT_DEVICE_SIZE		18
106 #define USB_DT_CONFIG_SIZE		9
107 #define USB_DT_INTERFACE_SIZE		9
108 #define USB_DT_ENDPOINT_SIZE		7
109 #define USB_DT_ENDPOINT_AUDIO_SIZE	9	/* Audio extension */
110 #define USB_DT_HUB_NONVAR_SIZE		7
111 
112 /*
113  * Standard requests
114  */
115 #define USB_REQ_GET_STATUS              0x00
116 #define USB_REQ_CLEAR_FEATURE           0x01
117 /* 0x02 is reserved */
118 #define USB_REQ_SET_FEATURE             0x03
119 /* 0x04 is reserved */
120 #define USB_REQ_SET_ADDRESS             0x05
121 #define USB_REQ_GET_DESCRIPTOR          0x06
122 #define USB_REQ_SET_DESCRIPTOR          0x07
123 #define USB_REQ_GET_CONFIGURATION       0x08
124 #define USB_REQ_SET_CONFIGURATION       0x09
125 #define USB_REQ_GET_INTERFACE           0x0A
126 #define USB_REQ_SET_INTERFACE           0x0B
127 #define USB_REQ_SYNCH_FRAME             0x0C
128 
129 #define USB_TYPE_STANDARD               (0x00 << 5)
130 #define USB_TYPE_CLASS                  (0x01 << 5)
131 #define USB_TYPE_VENDOR                 (0x02 << 5)
132 #define USB_TYPE_RESERVED               (0x03 << 5)
133 
134 #define USB_RECIP_DEVICE                0x00
135 #define USB_RECIP_INTERFACE             0x01
136 #define USB_RECIP_ENDPOINT              0x02
137 #define USB_RECIP_OTHER                 0x03
138 
139 /*
140  * Various libusb API related stuff
141  */
142 #define USB_ENDPOINT_IN                 0x80
143 #define USB_ENDPOINT_OUT                0x00
144 /*!
145  * end of USB spec information
146  *********************************************************/
147 
148 /*!
149  * HID definitions
150  */
151 #define HID_REPORT_TYPE_INPUT	0x01
152 #define HID_REPORT_TYPE_OUTPUT	0x02
153 #define HID_REPORT_TYPE_FEATURE	0x03
154 
155 #define REQUEST_TYPE_USB        0x80
156 #define REQUEST_TYPE_HID        0x81
157 #define REQUEST_TYPE_GET_REPORT 0xa1
158 #define REQUEST_TYPE_SET_REPORT 0x21
159 
160 #define MAX_REPORT_SIZE         0x1800
161 
162 /*!
163  * SHUT definitions - From Simplified SHUT spec
164  */
165 
166 #define SHUT_TYPE_REQUEST       0x01
167 #define SHUT_TYPE_RESPONSE      0x04
168 #define SHUT_TYPE_NOTIFY        0x05
169 #define SHUT_OK                 0x06
170 #define SHUT_NOK                0x15
171 /* sync signals are also used to set the notification level */
172 #define SHUT_SYNC               0x16 /* complete notifications - not yet managed */
173 				     /* but needed for some early Ellipse models */
174 #define SHUT_SYNC_LIGHT         0x17 /* partial notifications */
175 #define SHUT_SYNC_OFF           0x18 /* disable notifications - only do polling */
176 #define SHUT_PKT_LAST           0x80
177 
178 #define SHUT_TIMEOUT 3000
179 
180 /*!
181  * SHUT functions for HID marshalling
182  */
183 int shut_get_descriptor(int upsfd, unsigned char type,
184 			unsigned char index, void *buf, int size);
185 int shut_get_string_simple(int upsfd, int index,
186 			   char *buf, size_t buflen);
187 int libshut_get_report(int upsfd, int ReportId,
188 		       unsigned char *raw_buf, int ReportSize );
189 int shut_set_report(int upsfd, int id, unsigned char *pkt, int reportlen);
190 int libshut_get_interrupt(int upsfd, unsigned char *buf,
191 			  int bufsize, int timeout);
192 void libshut_close(int upsfd);
193 
194 /* FIXME */
shut_strerror(void)195 const char * shut_strerror(void) { return ""; }
196 
197 /*!
198  * From SHUT specifications
199  * sync'ed with libusb
200  */
201 
202 typedef struct shut_ctrltransfer_s {
203 	uint8_t  bRequestType;
204 	uint8_t  bRequest;
205 	uint16_t wValue;
206 	uint16_t wIndex;
207 	uint16_t wLength;
208 
209 	uint32_t timeout;      /* in milliseconds */
210 
211 	/* pointer to data */
212 	void *data;
213 	/*   uint8_t  padding[8]; for use with shut_set_report?! */
214 } shut_ctrltransfer_t;
215 
216 
217 typedef union hid_data_t {
218 	shut_ctrltransfer_t  hid_pkt;
219 	uint8_t raw_pkt[8]; /* max report lengh, was 8 */
220 } hid_data_t;
221 
222 typedef struct shut_packet_s {
223 	uint8_t bType;
224 	uint8_t bLength;
225 	hid_data_t    data;
226 	uint8_t bChecksum;
227 } shut_packet_t;
228 
229 typedef union shut_data_t {
230 	shut_packet_t shut_pkt;
231 	uint8_t raw_pkt[11];
232 } shut_data_t;
233 
234 typedef union hid_desc_data_t {
235 	struct my_hid_descriptor hid_desc;
236 	uint8_t    raw_desc[9]; /* max report lengh, aws 9 */
237 } hid_desc_data_t;
238 
239 /* Device descriptor */
240 typedef struct device_descriptor_s {
241 	uint8_t  bLength;
242 	uint8_t  bDescriptorType;
243 	uint16_t bcdUSB;
244 	uint8_t  bDeviceClass;
245 	uint8_t  bDeviceSubClass;
246 	uint8_t  bDeviceProtocol;
247 	uint8_t  bMaxPacketSize0;
248 	uint16_t idVendor;
249 	uint16_t idProduct;
250 	uint16_t bcdDevice;
251 	uint8_t  iManufacturer;
252 	uint8_t  iProduct;
253 	uint8_t  iSerialNumber;
254 	uint8_t  bNumConfigurations;
255 } device_descriptor_t;
256 #if 0
257 typedef union device_desc_data_t {
258 	device_descriptor_t dev_desc;
259 	uint8_t       raw_desc[18];
260 } device_desc_data_t;
261 #endif
262 /* Low level SHUT (Serial HID UPS Transfer) routines  */
263 void setline(int upsfd, int set);
264 int shut_synchronise(int upsfd);
265 int shut_wait_ack(int upsfd);
266 int shut_interrupt_read(int upsfd, int ep, unsigned char *bytes,
267 			int size, int timeout);
268 int shut_control_msg(int upsfd, int requesttype, int request, int value,
269 		     int index, unsigned char *bytes, int size, int timeout);
270 
271 /* Data portability */
272 /* realign packet data according to Endianess */
273 #define BYTESWAP(in) (((in & 0xFF) << 8) + ((in & 0xFF00) >> 8))
align_request(struct shut_ctrltransfer_s * ctrl)274 static void align_request(struct shut_ctrltransfer_s *ctrl )
275 {
276 #if WORDS_BIGENDIAN
277         /* Sparc/Mips/... are big endian, USB/SHUT little endian */
278 	(*ctrl).wValue    = BYTESWAP((*ctrl).wValue);
279 	(*ctrl).wIndex    = BYTESWAP((*ctrl).wIndex);
280 	(*ctrl).wLength   = BYTESWAP((*ctrl).wLength);
281 #endif
282 }
283 
284 /* On success, fill in the curDevice structure and return the report
285  * descriptor length. On failure, return -1.
286  * Note: When callback is not NULL, the report descriptor will be
287  * passed to this function together with the upsfd and SHUTDevice_t
288  * information. This callback should return a value > 0 if the device
289  * is accepted, or < 1 if not.
290  */
libshut_open(int * upsfd,SHUTDevice_t * curDevice,char * device_path,int (* callback)(int upsfd,SHUTDevice_t * hd,unsigned char * rdbuf,int rdlen))291 int libshut_open(int *upsfd, SHUTDevice_t *curDevice, char *device_path,
292 	int (*callback)(int upsfd, SHUTDevice_t *hd, unsigned char *rdbuf, int rdlen))
293 {
294 	int ret, res;
295 	unsigned char buf[20];
296 	char string[MAX_STRING_SIZE];
297 	struct my_hid_descriptor *desc;
298 	struct device_descriptor_s *dev_descriptor;
299 
300 	/* report descriptor */
301 	unsigned char	rdbuf[MAX_REPORT_SIZE];
302 	int		rdlen;
303 	/* All devices use HID descriptor at index 0. However, some newer
304 	 * Eaton units have a light HID descriptor at index 0, and the full
305 	 * version is at index 1 (in which case, bcdDevice == 0x0202) */
306 	int hid_desc_index = 0;
307 
308 	upsdebugx(2, "libshut_open: using port %s", device_path);
309 
310 	/* If device is still open, close it */
311 	if (*upsfd > 0) {
312 		ser_close(*upsfd, device_path);
313 	}
314 
315 	/* initialize serial port */
316 	/* FIXME: add variable baudrate detection */
317 	*upsfd = ser_open(device_path);
318 	ser_set_speed(*upsfd, device_path, B2400);
319 	setline(*upsfd, 1);
320 
321 	/* initialise communication */
322 	if (!shut_synchronise(*upsfd))
323 	{
324 		upsdebugx(2, "No communication with UPS");
325 		return -1;
326 	}
327 
328 	upsdebugx(2, "Communication with UPS established");
329 
330 	/* we can skip the rest due to serial bus specifics! */
331 	if (!callback) {
332 		return 1;
333 	}
334 
335 	/* Get DEVICE descriptor */
336 	dev_descriptor = (struct device_descriptor_s *)buf;
337 	res = shut_get_descriptor(*upsfd, USB_DT_DEVICE, 0, buf, USB_DT_DEVICE_SIZE);
338 	/* res = shut_control_msg(devp, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR,
339 	(USB_DT_DEVICE << 8) + 0, 0, buf, 0x9, SHUT_TIMEOUT); */
340 	if (res < 0)
341 	{
342 		upsdebugx(2, "Unable to get DEVICE descriptor (%s)", shut_strerror());
343 		return -1;
344 	}
345 
346 	if (res < 9)
347 	{
348 		upsdebugx(2, "DEVICE descriptor too short (expected %d, got %d)",
349 		      USB_DT_DEVICE_SIZE, res);
350 		return -1;
351 	}
352 
353 	/* collect the identifying information of this
354 		device. Note that this is safe, because
355 		there's no need to claim an interface for
356 		this (and therefore we do not yet need to
357 		detach any kernel drivers). */
358 
359 	free(curDevice->Vendor);
360 	free(curDevice->Product);
361 	free(curDevice->Serial);
362 	free(curDevice->Bus);
363 	memset(curDevice, '\0', sizeof(*curDevice));
364 
365 	curDevice->VendorID = dev_descriptor->idVendor;
366 	curDevice->ProductID = dev_descriptor->idProduct;
367 	curDevice->Bus = strdup("serial");
368 	curDevice->bcdDevice = dev_descriptor->bcdDevice;
369 	curDevice->Vendor = strdup("Eaton");
370 	if (dev_descriptor->iManufacturer) {
371 		ret = shut_get_string_simple(*upsfd, dev_descriptor->iManufacturer,
372 			string, MAX_STRING_SIZE);
373 		if (ret > 0) {
374 			curDevice->Vendor = strdup(string);
375 		}
376 	}
377 
378 	/* ensure iProduct retrieval */
379 	if (dev_descriptor->iProduct) {
380 		ret = shut_get_string_simple(*upsfd, dev_descriptor->iProduct, string, MAX_STRING_SIZE);
381 	} else {
382 		ret = 0;
383 	}
384 	if (ret > 0) {
385 		curDevice->Product = strdup(string);
386 	} else {
387 		curDevice->Product = strdup("unknown");
388 	}
389 
390 	if (dev_descriptor->iSerialNumber) {
391 		ret = shut_get_string_simple(*upsfd, dev_descriptor->iSerialNumber, string, 0x25);
392 	} else {
393 		ret = 0;
394 	}
395 
396 	if (ret > 0) {
397 		curDevice->Serial = strdup(string);
398 	} else {
399 		curDevice->Serial = strdup("unknown");
400 	}
401 
402 	upsdebugx(2, "- VendorID: %04x", curDevice->VendorID);
403 	upsdebugx(2, "- ProductID: %04x", curDevice->ProductID);
404 	upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor);
405 	upsdebugx(2, "- Product: %s", curDevice->Product);
406 	upsdebugx(2, "- Serial Number: %s", curDevice->Serial);
407 	upsdebugx(2, "- Bus: %s", curDevice->Bus);
408 	upsdebugx(2, "- Device release number: %04x", curDevice->bcdDevice);
409 	upsdebugx(2, "Device matches");
410 
411 	if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) {
412 			upsdebugx(1, "Eaton device v2.02. Using full report descriptor");
413 			hid_desc_index = 1;
414 	}
415 
416 	/* Get HID descriptor */
417 	desc = (struct my_hid_descriptor *)buf;
418 	res = shut_get_descriptor(*upsfd, USB_DT_HID, hid_desc_index, buf, 0x9);
419 	/* res = shut_control_msg(devp, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR,
420 			(USB_DT_HID << 8) + 0, 0, buf, 0x9, SHUT_TIMEOUT); */
421 
422 	if (res < 0)
423 	{
424 		upsdebugx(2, "Unable to get HID descriptor (%s)", shut_strerror());
425 		return -1;
426 	}
427 
428 	if (res < 9)
429 	{
430 		upsdebugx(2, "HID descriptor too short (expected %d, got %d)", 8, res);
431 		return -1;
432 	}
433 
434 	/* USB_LE16_TO_CPU(desc->wDescriptorLength); */
435 	desc->wDescriptorLength = buf[7] | (buf[8] << 8);
436 	upsdebugx(2, "HID descriptor retrieved (Reportlen = %u)", desc->wDescriptorLength);
437 
438 /*	if (!dev->config) {
439 		upsdebugx(2, "  Couldn't retrieve descriptors");
440 		return -1;
441 	}*/
442 
443 	rdlen = desc->wDescriptorLength;
444 
445 	if (rdlen > (int)sizeof(rdbuf)) {
446 		upsdebugx(2, "HID descriptor too long %d (max %d)", rdlen, (int)sizeof(rdbuf));
447 		return -1;
448 	}
449 
450 	/* Get REPORT descriptor */
451 	res = shut_get_descriptor(*upsfd, USB_DT_REPORT, hid_desc_index, rdbuf, rdlen);
452 	/* res = shut_control_msg(devp, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR,
453 				(USB_DT_REPORT << 8) + 0, 0, ReportDesc,
454 			desc->wDescriptorLength, SHUT_TIMEOUT); */
455 	if (res == rdlen)
456 	{
457 		res = callback(*upsfd, curDevice, rdbuf, rdlen);
458 		if (res < 1) {
459 			upsdebugx(2, "Caller doesn't like this device");
460 			return -1;
461 		}
462 
463 		upsdebugx(2, "Report descriptor retrieved (Reportlen = %d)", rdlen);
464 		upsdebugx(2, "Found HID device");
465 		fflush(stdout);
466 
467 		return rdlen;
468 	}
469 
470 	if (res < 0)
471 	{
472 		upsdebugx(2, "Unable to get Report descriptor (%d)", res);
473 	}
474 	else
475 	{
476 		upsdebugx(2, "Report descriptor too short (expected %d, got %d)", rdlen, res);
477 	}
478 
479 	upsdebugx(2, "No appropriate HID device found");
480 	fflush(stdout);
481 
482 	return -1;
483 }
484 
libshut_close(int upsfd)485 void libshut_close(int upsfd)
486 {
487 	if (upsfd < 1) {
488 		return;
489 	}
490 
491 	ser_close(upsfd, NULL);
492 }
493 
494 /* return the report of ID=type in report
495  * return -1 on failure, report length on success
496  */
libshut_get_report(int upsfd,int ReportId,unsigned char * raw_buf,int ReportSize)497 int libshut_get_report(int upsfd, int ReportId,
498 		       unsigned char *raw_buf, int ReportSize )
499 {
500 	if (upsfd < 1) {
501 		return 0;
502 	}
503 
504 	upsdebugx(4, "Entering libshut_get_report");
505 
506 	return shut_control_msg(upsfd,
507 		REQUEST_TYPE_GET_REPORT,
508 		/* == USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE, */
509 		 0x01,
510 		 ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */
511 		 0, raw_buf, ReportSize, SHUT_TIMEOUT);
512 }
513 
514 /* return ReportSize upon success ; -1 otherwise */
libshut_set_report(int upsfd,int ReportId,unsigned char * raw_buf,int ReportSize)515 int libshut_set_report(int upsfd, int ReportId,
516 		       unsigned char *raw_buf, int ReportSize )
517 {
518 	int ret;
519 
520 	if (upsfd < 1) {
521 		return 0;
522 	}
523 
524 	upsdebugx(1, "Entering libshut_set_report (report %x, len %i)",
525 		ReportId, ReportSize);
526 
527 	upsdebug_hex (4, "==> Report after set", raw_buf, ReportSize);
528 
529 	ret = shut_control_msg(upsfd,
530 		REQUEST_TYPE_SET_REPORT,
531 		/* == USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, */
532 		0x09,
533 		ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */
534 		0, raw_buf, ReportSize, SHUT_TIMEOUT);
535 
536 	return ((ret == 0) ? ReportSize : ret);
537 }
538 
libshut_get_string(int upsfd,int StringIdx,char * buf,size_t buflen)539 int libshut_get_string(int upsfd, int StringIdx, char *buf, size_t buflen)
540 {
541 	int ret;
542 
543 	if (upsfd < 1) {
544 		return -1;
545 	}
546 
547 	ret = shut_get_string_simple(upsfd, StringIdx, buf, buflen);
548 	if (ret > 0)
549 		upsdebugx(2, "-> String: %s (len = %i/%i)", buf, ret, (int)buflen);
550 	else
551 		upsdebugx(2, "- Unable to fetch buf");
552 
553 	return ret;
554 }
555 
libshut_get_interrupt(int upsfd,unsigned char * buf,int bufsize,int timeout)556 int libshut_get_interrupt(int upsfd, unsigned char *buf,
557 			   int bufsize, int timeout)
558 {
559 	int ret;
560 
561 	if (upsfd < 1) {
562 		return -1;
563 	}
564 
565 	/* FIXME: hardcoded interrupt EP => need to get EP descr for IF descr */
566 	ret = shut_interrupt_read(upsfd, 0x81, buf, bufsize, timeout);
567 	if (ret > 0)
568 		upsdebugx(6, " ok");
569 	else
570 		upsdebugx(6, " none (%i)", ret);
571 
572 	return ret;
573 }
574 
575 shut_communication_subdriver_t shut_subdriver = {
576 	SHUT_DRIVER_NAME,
577 	SHUT_DRIVER_VERSION,
578 	libshut_open,
579 	libshut_close,
580 	libshut_get_report,
581 	libshut_set_report,
582 	libshut_get_string,
583 	libshut_get_interrupt
584 };
585 
586 /***********************************************************************/
587 /********** Low level SHUT (Serial HID UPS Transfer) routines **********/
588 /***********************************************************************/
589 
590 /*
591  * set RTS to on and DTR to off
592  *
593  * set : 1 to set comm
594  * set : 0 to stop commupsh.
595  */
setline(int upsfd,int set)596 void setline(int upsfd, int set)
597 {
598 	if (upsfd < 1) {
599 		return;
600 	}
601 
602 	upsdebugx(3, "entering setline(%i)", set);
603 
604 	if (set == 1) {
605 		ser_set_dtr(upsfd, 0);
606 		ser_set_rts(upsfd, 1);
607 	} else {
608 		ser_set_dtr(upsfd, 1);
609 		ser_set_rts(upsfd, 0);
610 	}
611 }
612 
613 /*****************************************************************************
614  * shut_synchronise ()
615  *
616  * initiate communication with the UPS
617  *
618  * return TRUE on success, FALSE on failure
619  *
620  *****************************************************************************/
shut_synchronise(int upsfd)621 int shut_synchronise(int upsfd)
622 {
623 	int retCode = 0;
624 	u_char c = SHUT_SYNC_OFF, reply;
625 	int try;
626 
627 	upsdebugx (2, "entering shut_synchronise()");
628 	reply = '\0';
629 
630 	/* FIXME: re enable notification support?
631 	switch (notification)
632 	{
633 		case OFF_NOTIFICATION:
634 			c = SHUT_SYNC_OFF;
635 			break;
636 		case LIGHT_NOTIFICATION:
637 			c = SHUT_SYNC_LIGHT;
638 			break;
639 		default:
640 		case COMPLETE_NOTIFICATION:
641 			c = SHUT_SYNC;
642 			break;
643 	}
644 	*/
645 
646 	/* Sync with the UPS according to notification */
647 	for (try = 0; try < MAX_TRY; try++)
648 	{
649 		upsdebugx (3, "Syncing communication (try %i)", try);
650 
651 		if ((ser_send_char(upsfd, c)) == -1)
652 		{
653 			upsdebugx (3, "Communication error while writing to port");
654 			continue;
655 		}
656 
657 		ser_get_char(upsfd, &reply, 1, 0);
658 		if (reply == c)
659 		{
660 			upsdebugx (3, "Syncing and notification setting done");
661 			return 1;
662 		}
663 	}
664 	return retCode;
665 }
666 
667 /*!
668  * Compute a SHUT checksum for the packet "buf"
669  */
shut_checksum(const u_char * buf,int bufsize)670 u_char shut_checksum(const u_char *buf, int bufsize)
671 {
672 	int i;
673 	u_char chk=0;
674 
675 	for(i=0; i<bufsize; i++)
676 		chk^=buf[i];
677 
678 	upsdebugx (4, "shut_checksum: %02x", chk);
679 	return chk;
680 }
681 
682 
shut_packet_recv(int upsfd,u_char * Buf,int datalen)683 int shut_packet_recv(int upsfd, u_char *Buf, int datalen)
684 {
685 	u_char   Start[2];
686 	u_char   Frame[8];
687 	u_char   Chk[1];
688 	u_short  Size=8;
689 	u_short  Pos=0;
690 	u_char   Retry=0;
691 	int recv;
692 	/* FIXME: use this
693 	 * shut_data_t   sdata; */
694 
695 	upsdebugx (4, "entering shut_packet_recv (%i)", datalen);
696 
697 	while(datalen>0 && Retry<3)
698 	{
699 		/* if(serial_read (SHUT_TIMEOUT, &Start[0]) > 0) */
700 		if(ser_get_char(upsfd, &Start[0], SHUT_TIMEOUT/1000, 0) > 0)
701 		{
702 			/* sdata.shut_pkt.bType = Start[0]; */
703 			if(Start[0]==SHUT_SYNC)
704 			{
705 				upsdebugx (4, "received SYNC token");
706 				memcpy(Buf, Start, 1);
707 				return 1;
708 			}
709 			else if(Start[0]==SHUT_SYNC_OFF)
710 			{
711 				upsdebugx (4, "received SYNC_OFF token");
712 				memcpy(Buf, Start, 1);
713 				return 1;
714 			}
715 			else
716 			{
717 				/* if((serial_read (SHUT_TIMEOUT, &Start[1]) > 0) && */
718 				if( (ser_get_char(upsfd, &Start[1], SHUT_TIMEOUT/1000, 0) > 0) &&
719 							((Start[1]>>4)==(Start[1]&0x0F)))
720 				{
721 					upsdebug_hex(4, "Receive", Start, 2);
722 					Size=Start[1]&0x0F;
723 					if( Size > 8 ) {
724 						upsdebugx (4, "shut_packet_recv: invalid frame size = %d", Size);
725 						ser_send_char(upsfd, SHUT_NOK);
726 						Retry++;
727 						break;
728 					}
729 					/* sdata.shut_pkt.bLength = Size; */
730 					for(recv=0;recv<Size;recv++)
731 					{
732 						/* if(serial_read (SHUT_TIMEOUT, &Frame[recv]) < 1) */
733 						if(ser_get_char(upsfd, &Frame[recv], SHUT_TIMEOUT/1000, 0) < 1)
734 							break;
735 					}
736 					upsdebug_hex(4, "Receive", Frame, Size);
737 
738 					/* serial_read (SHUT_TIMEOUT, &Chk[0]); */
739 					ser_get_char(upsfd, &Chk[0], SHUT_TIMEOUT/1000, 0);
740 					if(Chk[0]==shut_checksum(Frame, Size))
741 					{
742 						upsdebugx (4, "shut_checksum: %02x => OK", Chk[0]);
743 						memcpy(Buf, Frame, Size);
744 						datalen-=Size;
745 						Buf+=Size;
746 						Pos+=Size;
747 						Retry=0;
748 
749 						ser_send_char(upsfd, SHUT_OK);
750 						/* shut_token_send(SHUT_OK); */
751 
752 						/* Check if there are more data to receive */
753 						if((Start[0] & 0xf0) == SHUT_PKT_LAST)
754 						{
755 							/* Check if it's a notification */
756 							if ((Start[0] & 0x0f) == SHUT_TYPE_NOTIFY)
757 							{
758 								/* TODO: process notification (dropped for now) */
759 								upsdebugx (4, "=> notification");
760 								datalen+=Pos;
761 								Pos=0;
762 							}
763 							else
764 								return Pos;
765 						}
766 						else
767 							upsdebugx (4, "need more data (%i)!", datalen);
768 					}
769 					else
770 					{
771 						upsdebugx (4, "shut_checksum: %02x => NOK", Chk[0]);
772 						ser_send_char(upsfd, SHUT_NOK);
773 						/* shut_token_send(SHUT_NOK); */
774 						Retry++;
775 					}
776 				}
777 				else
778 					return 0;
779 			}
780 		}
781 		else
782 			Retry++;
783 	} /* while */
784 
785 	return 0;
786 }
787 
788 /**********************************************************************/
shut_interrupt_read(int upsfd,int ep,unsigned char * bytes,int size,int timeout)789 int shut_interrupt_read(int upsfd, int ep, unsigned char *bytes, int size,
790 		       int timeout)
791 {
792 /*
793 	usleep(timeout * 1000);
794  */
795 	/* FIXME: to be written */
796 	return 0;
797 }
798 
799 /**********************************************************************/
shut_get_string_simple(int upsfd,int index,char * buf,size_t buflen)800 int shut_get_string_simple(int upsfd, int index,
801 			   char *buf, size_t buflen)
802 {
803 	unsigned char tbuf[255];       /* Some devices choke on size > 255 */
804 	int ret, si, di;
805 
806 	ret = shut_control_msg(upsfd, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
807 			(USB_DT_STRING << 8) + index, 0x0, tbuf, buflen, SHUT_TIMEOUT);
808 	if (ret < 0)
809 		return ret;
810 
811 	if (tbuf[1] != USB_DT_STRING)
812 		return -EIO;
813 
814 	if (tbuf[0] > ret)
815 		return -EFBIG;
816 
817 	/* skip the UTF8 zero'ed high bytes */
818 	for (di = 0, si = 2; si < tbuf[0]; si += 2)
819 	{
820 		if (di >= (int)(buflen - 1))
821 			break;
822 
823 		if (tbuf[si + 1])   /* high byte */
824 			buf[di++] = '?';
825 		else
826 			buf[di++] = tbuf[si];
827 	}
828 
829 	buf[di] = 0;
830 	return di;
831 }
832 
833 /*
834  * Human Interface Device (HID) functions
835  *********************************************************************/
836 
837 /**********************************************************************
838  * shut_get_descriptor(int desctype, u_char *pkt)
839  *
840  * get descriptor specified by DescType and return it in Buf
841  *
842  * desctype  - from shutdataType
843  * pkt       - where to store the report received
844  *
845  * return 0 on success, -1 on failure, -2 on NACK
846  *
847  *********************************************************************/
shut_get_descriptor(int upsfd,unsigned char type,unsigned char index,void * buf,int size)848 int shut_get_descriptor(int upsfd, unsigned char type,
849 			unsigned char index, void *buf, int size)
850 {
851 	memset(buf, 0, size);
852 
853 	upsdebugx (2, "entering shut_get_descriptor(n %02x, %i)", type, size);
854 
855 	return shut_control_msg(upsfd, USB_ENDPOINT_IN+(type>=USB_DT_HID?1:0),
856 				 USB_REQ_GET_DESCRIPTOR, (type << 8) + index, 0, buf, size, SHUT_TIMEOUT);
857 }
858 
859 /* Take care of a SHUT transfer (sending and receiving data) */
shut_control_msg(int upsfd,int requesttype,int request,int value,int index,unsigned char * bytes,int size,int timeout)860 int shut_control_msg(int upsfd, int requesttype, int request,
861 		    int value, int index, unsigned char *bytes, int size, int timeout)
862 {
863 	unsigned char shut_pkt[11];
864 	short Retry=1, set_pass = -1;
865 	short data_size, remaining_size = size;
866 	int i;
867 	struct shut_ctrltransfer_s ctrl;
868 	int ret = 0;
869 
870 	upsdebugx (3, "entering shut_control_msg");
871 
872 	/* deal for set requests */
873 	if (requesttype == REQUEST_TYPE_SET_REPORT)
874 	{
875 		set_pass = 1;
876 		/* add 8 for the first frame that declares a coming set */
877 		remaining_size+= 8;
878 	}
879 
880 	/* build the control request */
881 	ctrl.bRequestType = requesttype;
882 	ctrl.bRequest = request;
883 	ctrl.wValue = value;
884 	ctrl.wIndex = index;
885 	ctrl.wLength = size;
886 	ctrl.data = bytes;
887 	ctrl.timeout = timeout;
888 
889 	align_request(&ctrl);
890 
891 	/* Send all data */
892 	while(remaining_size > 0 && Retry > 0) {
893 
894 		if (requesttype == REQUEST_TYPE_SET_REPORT) {
895 			if (set_pass == 1) {
896 				data_size = 8;
897 				set_pass++; /* prepare for the next step */
898 			}
899 			else {
900 				data_size = size;
901 				upsdebug_hex(4, "data", bytes, data_size);
902 			}
903 		}
904 		else {
905 			/* Always 8 bytes payload for GET_REPORT with SHUT */
906 			data_size = 8;
907 		}
908 
909 		/* Forge the SHUT Frame */
910 		shut_pkt[0] = SHUT_TYPE_REQUEST + ( ((requesttype == REQUEST_TYPE_SET_REPORT) && (remaining_size>8))? 0 : SHUT_PKT_LAST);
911 		shut_pkt[1] = (data_size<<4) + data_size;
912 		if ( (requesttype == REQUEST_TYPE_SET_REPORT) && (remaining_size < 8) )
913 			memcpy(&shut_pkt[2], bytes, data_size); /* we need to send ctrl.data  */
914 		else
915 			memcpy(&shut_pkt[2], &ctrl, 8);
916 		shut_pkt[(data_size+3) - 1] = shut_checksum(&shut_pkt[2], data_size);
917 
918 		/* Packets need only to be sent once
919 		* NACK handling should take care of the rest */
920 		if (Retry == 1)
921 		{
922 			ser_send_buf(upsfd, shut_pkt, data_size+3);
923 			upsdebug_hex(3, "shut_control_msg", shut_pkt, data_size+3);
924 			/* serial_send (shut_pkt, data_size+3); */
925 		}
926 
927 		i = shut_wait_ack (upsfd);
928 		switch (i)
929 		{
930 			case 0:
931 				if (requesttype == REQUEST_TYPE_SET_REPORT)
932 					remaining_size-=data_size;
933 				else
934 					remaining_size = 0;
935 
936 				Retry=1;
937 				break;
938 			case -1:
939 				if (Retry >= MAX_TRY)
940 				{
941 					upsdebugx(2, "Max tries reached while waiting for ACK, still getting errors");
942 
943 					/* try to resync, and give one more try */
944 					Retry--;
945 					shut_synchronise(upsfd);
946 					return i;
947 				}
948 				else
949 				{
950 					upsdebugx(4, "Retry = %i", Retry);
951 					/* Send a NACK to get a resend from the UPS */
952 					ser_send_char(upsfd, SHUT_NOK);
953 					Retry++;
954 				}
955 				break;
956 			case -3:
957 				/* FIXME: notification caught => to be processed */
958 
959 				/* Send a NACK for the moment, to get a resend from the UPS */
960 				ser_send_char(upsfd, SHUT_NOK);
961 				Retry++;
962 			default:
963 				;
964 		}
965 	}
966 	if (remaining_size != 0)
967 		return -1;
968 
969 	/* now receive data, except for SET_REPORT */
970 	if (requesttype != REQUEST_TYPE_SET_REPORT)
971 		ret = shut_packet_recv (upsfd, bytes, size);
972 
973 	return ret;
974 }
975 
976 /**********************************************************************
977  * shut_wait_ack()
978  *
979  * wait for an ACK packet
980  *
981  * returns 0 on success, -1 on error, -2 on NACK, -3 on NOTIFICATION
982  *
983  *********************************************************************/
shut_wait_ack(int upsfd)984 int shut_wait_ack(int upsfd)
985 {
986 	int retCode = -1;
987 	u_char c = '\0';
988 
989 	ser_get_char(upsfd, &c, SHUT_TIMEOUT/1000, 0);
990 	if (c == SHUT_OK)
991 	{
992 		upsdebugx (2, "shut_wait_ack(): ACK received");
993 		retCode = 0;
994 	}
995 	else if (c == SHUT_NOK)
996 	{
997 		upsdebugx (2, "shut_wait_ack(): NACK received");
998 		retCode = -2;
999 	}
1000 	else if ((c & 0x0f) == SHUT_TYPE_NOTIFY)
1001 	{
1002 		upsdebugx (2, "shut_wait_ack(): NOTIFY received");
1003 		retCode = -3;
1004 	}
1005 	else if (c == '\0')
1006 		upsdebugx (2, "shut_wait_ack(): Nothing received");
1007 
1008 	return retCode;
1009 }
1010