~ubuntu-branches/ubuntu/saucy/nut/saucy

« back to all changes in this revision

Viewing changes to drivers/libhid.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Quette
  • Date: 2004-05-28 13:10:01 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040528131001-yj2m9qcez4ya2w14
Tags: upstream-1.4.2
ImportĀ upstreamĀ versionĀ 1.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*!
 
2
 * @file libhid.c
 
3
 * @brief HID Library - User API (Generic HID Access using MGE HIDParser)
 
4
 *
 
5
 * @author Copyright (C) 2003
 
6
 *      Arnaud Quette <arnaud.quette@free.fr> && <arnaud.quette@mgeups.com>
 
7
 *      Philippe Marzouk <philm@users.sourceforge.net> (dump_hex())
 
8
 *
 
9
 * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com
 
10
 *
 
11
 *      The logic of this file is ripped from mge-shut driver (also from
 
12
 *      Arnaud Quette), which is a "HID over serial link" UPS driver for
 
13
 *      Network UPS Tools <http://www.networkupstools.org/>
 
14
 *
 
15
 *      This program is free software; you can redistribute it and/or modify
 
16
 *      it under the terms of the GNU General Public License as published by
 
17
 *      the Free Software Foundation; either version 2 of the License, or
 
18
 *      (at your option) any later version.
 
19
 *
 
20
 *      This program is distributed in the hope that it will be useful,
 
21
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
23
 *      GNU General Public License for more details.
 
24
 *
 
25
 *      You should have received a copy of the GNU General Public License
 
26
 *      along with this program; if not, write to the Free Software
 
27
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
28
 *
 
29
 * -------------------------------------------------------------------------- */
 
30
 
 
31
#include <stdio.h>
 
32
#include <string.h>
 
33
/* #include <math.h> */
 
34
#include "hidparser.h"
 
35
#include "hidtypes.h"
 
36
#include "libhid.h"
 
37
 
 
38
#include "hid-usb.h"
 
39
 
 
40
HIDDevice curDevice;
 
41
 
 
42
static HIDData          hData;
 
43
static HIDParser        hParser;
 
44
 
 
45
unsigned char raw_buf[100];
 
46
int replen; /* size of the last report retrieved */
 
47
unsigned char ReportDesc[4096];
 
48
 
 
49
#define MAX_REPORT_SIZE         0x1800
 
50
 
 
51
/* TODO: rework all that */
 
52
extern void upsdebugx(int level, const char *fmt, ...);
 
53
#define TRACE upsdebugx
 
54
 
 
55
/* Units and exponents table (HID PDC, ļæ½3.2.3) */
 
56
#define NB_HID_UNITS 10
 
57
const long HIDUnits[NB_HID_UNITS][2]=
 
58
{
 
59
  {0x00000000,0}, /* None */
 
60
  {0x00F0D121,7}, /* Voltage */
 
61
  {0x00100001,0}, /* Ampere */
 
62
  {0x0000D121,7}, /* VA */
 
63
  {0x0000D121,7}, /* Watts */
 
64
  {0x00001001,0}, /* second */
 
65
  {0x00010001,0}, /* ļæ½K */
 
66
  {0x00000000,0}, /* percent */
 
67
  {0x0000F001,0}, /* Hertz */
 
68
  {0x00101001,0}, /* As */
 
69
};
 
70
 
 
71
/* support functions */
 
72
void logical_to_physical(HIDData *Data);
 
73
void physical_to_logical(HIDData *Data);
 
74
int hid_lookup_usage(char *name);
 
75
ushort lookup_path(const char *HIDpath, HIDData *data);
 
76
void dump_hex (const char *msg, const unsigned char *buf, int len);
 
77
long get_unit_expo(long UnitType);
 
78
float expo(int a, int b);
 
79
 
 
80
 
 
81
HIDDevice *HIDOpenDevice(const char *port, MatchFlags *flg)
 
82
{
 
83
  int ReportSize;
 
84
 
 
85
  /* Init structure */
 
86
  curDevice.Name = NULL;
 
87
  curDevice.Vendor = NULL;
 
88
  curDevice.VendorID = -1;
 
89
  curDevice.Product = NULL;
 
90
  curDevice.ProductID = -1;
 
91
  curDevice.Serial = NULL;
 
92
  curDevice.Application = -1;
 
93
  curDevice.fd = -1;
 
94
 
 
95
  /* get and parse descriptors (dev, cfg and report) */
 
96
  if ((ReportSize = libusb_open(&curDevice, flg, ReportDesc)) == -1) {
 
97
    return NULL;
 
98
  }
 
99
  else {
 
100
    TRACE(2, "Report Descriptor size = %d", ReportSize);
 
101
    dump_hex ("Report Descriptor", ReportDesc, 200);
 
102
 
 
103
    /* HID Parser Init */
 
104
    ResetParser(&hParser);
 
105
    hParser.ReportDescSize = ReportSize;
 
106
    memcpy(hParser.ReportDesc, ReportDesc, ReportSize);
 
107
    HIDParse(&hParser, &hData);
 
108
 
 
109
    /* CHeck for matching UsageCode (1rst collection == application == type of device) */
 
110
    if ((hData.Path.Node[0].UPage == ((flg->UsageCode & 0xFFFF0000) / 0x10000))
 
111
        && (hData.Path.Node[0].Usage == (flg->UsageCode & 0x0000FFFF)))
 
112
      TRACE(2, "Found a device matching UsageCode (0x%08x)", flg->UsageCode);
 
113
    else {
 
114
      TRACE(2, "Found a device, but not matching UsageCode (0x%08x)", flg->UsageCode);
 
115
      return NULL;
 
116
    }
 
117
  }
 
118
  return &curDevice;
 
119
}
 
120
 
 
121
HIDItem *HIDGetItem(const char *ItemPath)
 
122
{
 
123
  return NULL;
 
124
}
 
125
 
 
126
float HIDGetItemValue(const char *path)
 
127
{
 
128
  int i, retcode;
 
129
  float Value;
 
130
 
 
131
  /* Prepare path of HID object */
 
132
  hData.Type = ITEM_FEATURE;
 
133
  hData.ReportID = 0;
 
134
 
 
135
  if((retcode = lookup_path(path, &hData)) > 0) {
 
136
    TRACE(2, "Path depth = %i", retcode);
 
137
    
 
138
    for (i = 0; i<retcode; i++)
 
139
      TRACE(2, "%i: UPage(%x), Usage(%x)", i,
 
140
                hData.Path.Node[i].UPage,
 
141
                hData.Path.Node[i].Usage);
 
142
    
 
143
    hData.Path.Size = retcode;
 
144
 
 
145
    /* Get info on object (reportID, offset and size) */
 
146
    if (FindObject(&hParser,&hData) == 1) {
 
147
      /* Get report with data */
 
148
      /* if ((replen=libusb_get_report(hData.ReportID, 
 
149
         raw_buf, MAX_REPORT_SIZE)) > 0) { => doesn't work! */
 
150
      if ((replen=libusb_get_report(hData.ReportID, raw_buf, 10)) > 0) {
 
151
        /* Extract the data value */
 
152
        GetValue((const unsigned char *) raw_buf, &hData);
 
153
 
 
154
        TRACE(2, "=>> Before exponent: %ld, %i/%i)", hData.Value,
 
155
              (int)hData.UnitExp, (int)get_unit_expo(hData.Unit) );
 
156
 
 
157
        /* Convert Logical Min, Max and Value in Physical */
 
158
        /* logical_to_physical(&hData); */
 
159
 
 
160
        Value = hData.Value;
 
161
 
 
162
        /* Process exponents */
 
163
        /* Value*=(float) pow(10,(int)hData.UnitExp - get_unit_expo(hData.Unit)); */
 
164
        Value*=(float) expo(10,(int)hData.UnitExp - get_unit_expo(hData.Unit));
 
165
        hData.Value = (long) Value;
 
166
 
 
167
        /* Convert Logical Min, Max and Value into Physical */
 
168
        logical_to_physical(&hData);
 
169
 
 
170
        dump_hex ("Report ", raw_buf, replen);
 
171
 
 
172
        return Value;
 
173
      }
 
174
      else
 
175
        TRACE(2, "Can't retrieve Report %i", hData.ReportID);
 
176
//exit(-1);
 
177
    }
 
178
    else
 
179
      TRACE(2, "Can't find object %s", path);
 
180
  }
 
181
  return -2; /* TODO: should be checked */
 
182
}
 
183
 
 
184
char *HIDGetItemString(const char *path)
 
185
{
 
186
  int i, retcode;
 
187
  
 
188
  /* Prepare path of HID object */
 
189
  hData.Type = ITEM_FEATURE;
 
190
  hData.ReportID = 0;
 
191
  
 
192
  if((retcode = lookup_path(path, &hData)) > 0) {
 
193
    TRACE(2, "Path depth = %i", retcode);
 
194
    
 
195
    for (i = 0; i<retcode; i++)
 
196
      TRACE(2, "%i: UPage(%x), Usage(%x)", i,
 
197
                hData.Path.Node[i].UPage,
 
198
                hData.Path.Node[i].Usage);
 
199
    
 
200
    hData.Path.Size = retcode;
 
201
    
 
202
    /* Get info on object (reportID, offset and size) */
 
203
    if (FindObject(&hParser,&hData) == 1) {
 
204
      if (libusb_get_report(hData.ReportID, raw_buf, 8) > 0) { /* MAX_REPORT_SIZE) > 0) { */
 
205
        GetValue((const unsigned char *) raw_buf, &hData);
 
206
 
 
207
        /* now get string */
 
208
        libusb_get_string(hData.Value, raw_buf);
 
209
        return raw_buf;
 
210
      }
 
211
      else
 
212
        TRACE(2, "Can't retrieve Report %i", hData.ReportID);
 
213
    }
 
214
    else
 
215
      TRACE(2, "Can't find object %s", path);
 
216
 
 
217
    return NULL;
 
218
  }
 
219
  return NULL;
 
220
}
 
221
 
 
222
bool HIDSetItemValue(const char *path, float value)
 
223
{
 
224
  float Value;
 
225
 
 
226
  /* Begin by a standard Get to fill in com structures ... */
 
227
  Value = HIDGetItemValue(path);
 
228
 
 
229
  /* ... And play with global vars */
 
230
  if (Value != -2) { /* Get succeed */
 
231
 
 
232
    TRACE(2, "=>> SET: Before set: %.2f (%ld)", Value, (long)value);
 
233
 
 
234
    /* Test if Item is settable */
 
235
    if (hData.Attribute != ATTR_DATA_CST) {
 
236
      /* Set new value for this item */
 
237
      /* And Process exponents restoration */
 
238
      Value = value * expo(10, get_unit_expo(hData.Unit) - (int)hData.UnitExp);
 
239
 
 
240
      hData.Value=(long) Value;
 
241
 
 
242
      TRACE(2, "=>> SET: after exp: %ld/%.2f (exp = %.2f)", hData.Value, Value,
 
243
             expo(10, (int)get_unit_expo(hData.Unit) - (int)hData.UnitExp));
 
244
 
 
245
      /* Convert Physical Min, Max and Value in Logical */
 
246
      physical_to_logical(&hData);
 
247
      TRACE(2, "=>> SET: after PL: %ld", hData.Value);
 
248
 
 
249
      SetValue(&hData, raw_buf);
 
250
 
 
251
      dump_hex ("==> Report after setvalue", raw_buf, replen);
 
252
 
 
253
      if (libusb_set_report(hData.ReportID, raw_buf, replen) > 0) {
 
254
        TRACE(2, "Set report succeeded");
 
255
        return TRUE;
 
256
      } else {
 
257
        TRACE(2, "Set report failed");
 
258
        return FALSE;
 
259
      }
 
260
      /* check if set succeed! => doesn't work on *Delay (decremented!) */
 
261
      /*      Value = HIDGetItemValue(path);
 
262
      
 
263
      TRACE(2, "=>> SET: new value = %.2f (was set to %.2f)\n", 
 
264
      Value, (float) value);
 
265
      return TRUE;*/ /* (Value == value); */
 
266
    }
 
267
  }
 
268
  return FALSE;
 
269
}
 
270
HIDItem *HIDGetNextEvent(HIDDevice *dev)
 
271
{
 
272
  /*  unsigned char buf[20];
 
273
 
 
274
  upsdebugx(1, "Waiting for notifications\n");*/
 
275
 
 
276
  /* TODO: To be written */
 
277
  /* needs libusb-0.1.8 to work => use ifdef and autoconf */
 
278
  /* libusb_get_interrupt(&buf[0], 20, 5000); */
 
279
  return NULL;
 
280
}
 
281
void HIDCloseDevice(HIDDevice *dev)
 
282
{
 
283
  libusb_close(&curDevice);
 
284
}
 
285
 
 
286
 
 
287
/*******************************************************
 
288
 * support functions
 
289
 *******************************************************/
 
290
 
 
291
#define MAX_STRING                      64
 
292
 
 
293
void logical_to_physical(HIDData *Data)
 
294
{
 
295
  if(Data->PhyMax - Data->PhyMin > 0)
 
296
    {
 
297
      float Factor = (float)(Data->PhyMax - Data->PhyMin) / (Data->LogMax - Data->LogMin);
 
298
      /* Convert Value */
 
299
      Data->Value=(long)((Data->Value - Data->LogMin) * Factor) + Data->PhyMin;
 
300
 
 
301
      if(Data->Value > Data->PhyMax)
 
302
        Data->Value |= ~Data->PhyMax;
 
303
    }
 
304
  else /* => nothing to do!? */
 
305
    {
 
306
      /* Value.m_Value=(long)(pConvPrm->HValue); */
 
307
      if(Data->Value > Data->LogMax)
 
308
        Data->Value |= ~Data->LogMax;
 
309
    }
 
310
  
 
311
  /* if(Data->Value > Data->Value.m_Max)
 
312
    Value.m_Value |= ~Value.m_Max;
 
313
  */
 
314
}
 
315
 
 
316
void physical_to_logical(HIDData *Data)
 
317
{
 
318
  TRACE(2, "PhyMax = %ld, PhyMin = %ld, LogMax = %ld, LogMin = %ld",
 
319
        Data->PhyMax, Data->PhyMin, Data->LogMax, Data->LogMin);
 
320
 
 
321
  if(Data->PhyMax - Data->PhyMin > 0)
 
322
    {
 
323
      float Factor=(float)(Data->LogMax - Data->LogMin) / (Data->PhyMax - Data->PhyMin);
 
324
      /* Convert Value */
 
325
      Data->Value=(long)((Data->Value - Data->PhyMin) * Factor) + Data->LogMin;
 
326
    }
 
327
    /* else => nothing to do!?
 
328
       {
 
329
       m_ConverterTab[iTab].HValue=m_ConverterTab[iTab].DValue;
 
330
       } */
 
331
}
 
332
 
 
333
long get_unit_expo(long UnitType)
 
334
{
 
335
  int i = 0, exp = -1;
 
336
 
 
337
  while (i < NB_HID_UNITS) {
 
338
    if (HIDUnits[i][0] == UnitType) {
 
339
      exp = HIDUnits[i][1];
 
340
      break;
 
341
    }
 
342
    i++;
 
343
  }
 
344
  return exp;
 
345
}
 
346
 
 
347
/* exponent function: return a^b */
 
348
/* TODO: check if needed to replace libmath->pow */
 
349
float expo(int a, int b)
 
350
{
 
351
  if (b==0)
 
352
    return (float) 1;
 
353
  if (b>0)
 
354
    return (float) a * expo(a,b-1);
 
355
  if (b<0)
 
356
    return (float)((float)(1/(float)a) * (float) expo(a,b+1));
 
357
  
 
358
  /* not reached */
 
359
  return -1;
 
360
}
 
361
 
 
362
/* translate HID string path to numeric path and return path depth */
 
363
/* TODO: use usbutils functions (need to be externalised!) */
 
364
ushort lookup_path(const char *HIDpath, HIDData *data)
 
365
{
 
366
  ushort i = 0, cond = 1;
 
367
  int cur_usage;
 
368
  char buf[MAX_STRING];
 
369
  char *start, *end; 
 
370
  
 
371
  strncpy(buf, HIDpath, strlen(HIDpath));
 
372
  buf[strlen(HIDpath)] = '\0';
 
373
  start = end = buf;
 
374
  
 
375
  TRACE(2, "entering lookup_path(%s)", buf);
 
376
  
 
377
  while (cond) {
 
378
    
 
379
    if ((end = strchr(start, '.')) == NULL) {
 
380
      cond = 0;                 
 
381
    }
 
382
    else
 
383
      *end = '\0';
 
384
    
 
385
    TRACE(2, "parsing %s", start);
 
386
    
 
387
    /* lookup code */
 
388
    if ((cur_usage = hid_lookup_usage(start)) == -1) {
 
389
      TRACE(2, "%s wasn't found", start);
 
390
      return 0;
 
391
    }
 
392
    else {
 
393
      data->Path.Node[i].UPage = (cur_usage & 0xFFFF0000) / 0x10000;
 
394
      data->Path.Node[i].Usage = cur_usage & 0x0000FFFF; 
 
395
      i++; 
 
396
    }
 
397
    
 
398
    if(cond)
 
399
      start = end +1 ;
 
400
  }
 
401
  data->Path.Size = i;
 
402
  return i;
 
403
}
 
404
 
 
405
/* Lookup this usage name to find its code (page + index) */
 
406
/* temporary usage code lookup */
 
407
typedef struct {
 
408
        const char *usage_name;
 
409
        int usage_code;
 
410
} usage_lkp_t;
 
411
 
 
412
static usage_lkp_t usage_lkp[] = {
 
413
        /* Power Device Page */
 
414
        {  "PresentStatus", 0x00840002 },
 
415
        {  "UPS", 0x00840004 },
 
416
        {  "BatterySystem", 0x00840010 },
 
417
        {  "Battery", 0x00840012 },
 
418
        {  "BatteryID", 0x00840013 },   
 
419
        {  "PowerConverter", 0x00840016 },
 
420
        {  "OutletSystem", 0x00840018 },
 
421
        {  "Input", 0x0084001a },
 
422
        {  "Output", 0x0084001c },
 
423
        {  "Outlet", 0x00840020 },
 
424
        {  "OutletID", 0x00840021 },
 
425
        {  "PowerSummary", 0x00840024 },
 
426
        {  "Voltage", 0x00840030 },
 
427
        {  "Current", 0x00840031 },
 
428
        {  "Frequency", 0x00840032 },
 
429
        {  "PercentLoad", 0x00840035 },
 
430
        {  "Temperature", 0x00840036 },
 
431
        {  "ConfigVoltage", 0x00840040 },
 
432
        {  "ConfigCurrent", 0x00840041 },
 
433
        {  "ConfigFrequency", 0x00840042 },
 
434
        {  "ConfigApparentPower", 0x00840043 },
 
435
        {  "LowVoltageTransfer", 0x00840053 },
 
436
        {  "HighVoltageTransfer", 0x00840054 }, 
 
437
        {  "DelayBeforeReboot", 0x00840055 },   
 
438
        {  "DelayBeforeStartup", 0x00840056 },
 
439
        {  "DelayBeforeShutdown", 0x00840057 },
 
440
        {  "Test", 0x00840058 },
 
441
        {  "OverLoad", 0x00840065 }, /* mispelled in usb.ids */
 
442
        {  "ShutdownImminent", 0x00840069 },
 
443
        {  "SwitchOn/Off", 0x0084006b },
 
444
        {  "Switchable", 0x0084006c },
 
445
        {  "Boost", 0x0084006e },
 
446
        {  "Buck", 0x0084006f },
 
447
        {  "Flow", 0x0084001e },
 
448
        /* Battery System Page */
 
449
        {  "RemainingCapacityLimit", 0x00850029 },
 
450
        {  "BelowRemainingCapacityLimit", 0x00850042 },
 
451
        {  "RemainingCapacity", 0x00850066 },
 
452
        {  "RunTimeToEmpty", 0x00850068 },
 
453
        {  "ACPresent", 0x008500d0 },
 
454
        {  "Charging", 0x00850044 },
 
455
        {  "Discharging", 0x00850045 },
 
456
        {  "NeedReplacement", 0x0085004b },
 
457
/* TODO: per MFR specific usages */
 
458
        /* MGE UPS SYSTEMS Page */
 
459
        {  "iModel", 0xffff00f0 },
 
460
        {  "RemainingCapacityLimitSetting", 0xffff004d },
 
461
        {  "TestPeriod", 0xffff0045 },
 
462
        {  "LowVoltageBoostTransfer", 0xffff0050 },
 
463
        {  "HighVoltageBoostTransfer", 0xffff0051 },
 
464
        {  "LowVoltageBuckTransfer", 0xffff0052 },
 
465
        {  "HighVoltageBuckTransfer", 0xffff0053 },
 
466
        /* end of structure. */
 
467
        {  "\0", 0x0 }
 
468
};
 
469
 
 
470
int hid_lookup_usage(char *name)
 
471
{       
 
472
  int i;
 
473
        
 
474
  TRACE(2, "Looking up %s", name);
 
475
        
 
476
  if (name[0] == '[') /* manage indexed collection */
 
477
    return (0x00FF0000 + atoi(&name[1]));
 
478
  else {
 
479
    for (i = 0; (usage_lkp[i].usage_code != 0x0); i++)
 
480
      {
 
481
        if (!strcmp(usage_lkp[i].usage_name, name))
 
482
          {
 
483
            TRACE(2, "hid_lookup_usage: found %04x",
 
484
                      usage_lkp[i].usage_code);
 
485
            return usage_lkp[i].usage_code;
 
486
          }
 
487
      }
 
488
  }
 
489
  return -1;
 
490
}
 
491
 
 
492
#define NIBBLE(_i)    (((_i) < 10) ? '0' + (_i) : 'A' + (_i) - 10)
 
493
 
 
494
void dump_hex (const char *msg, const unsigned char *buf, int len)
 
495
{
 
496
  int i;
 
497
  int nlocal;
 
498
  const unsigned char *pc;
 
499
  char *out;
 
500
  const unsigned char *start;
 
501
  char c;
 
502
  char line[100];
 
503
  
 
504
  start = buf;
 
505
  out = line;
 
506
  
 
507
  for (i = 0, pc = buf, nlocal = len; i < 16; i++, pc++) {
 
508
    if (nlocal > 0) {
 
509
      c = *pc;
 
510
      
 
511
      *out++ = NIBBLE ((c >> 4) & 0xF);
 
512
      *out++ = NIBBLE (c & 0xF);
 
513
      
 
514
      nlocal--;
 
515
    }
 
516
    else {
 
517
      *out++ = ' ';
 
518
      *out++ = ' ';
 
519
    }                           /* end else */
 
520
    *out++ = ' ';
 
521
  }                             /* end for */
 
522
  *out++ = 0;
 
523
  
 
524
  TRACE(2, "%s: (%d bytes) => %s", msg, len, line);
 
525
  
 
526
  buf += 16;
 
527
  len -= 16;
 
528
} /* end dump */