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