aboutsummaryrefslogtreecommitdiff
path: root/usbhid
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2006-08-01 03:02:21 +0000
committerHans-Christoph Steiner <eighthave@users.sourceforge.net>2006-08-01 03:02:21 +0000
commite4294c52d38e682efbce61cc333b0ae7f1cdf219 (patch)
treefba6b0cc2ff99b50624cd9587db7460b6f692aa1 /usbhid
parente09f6b3090fa7f2ed5b82112d4b3b56222089e89 (diff)
separated usbhid into its own folder since it had dependencies that don't work on all platforms
svn path=/trunk/externals/hcs/; revision=5448
Diffstat (limited to 'usbhid')
-rw-r--r--usbhid/usbhid-help.pd139
-rw-r--r--usbhid/usbhid.c782
-rw-r--r--usbhid/usbhid.libs1
3 files changed, 922 insertions, 0 deletions
diff --git a/usbhid/usbhid-help.pd b/usbhid/usbhid-help.pd
new file mode 100644
index 0000000..08127b2
--- /dev/null
+++ b/usbhid/usbhid-help.pd
@@ -0,0 +1,139 @@
+#N canvas 254 84 629 549 10;
+#X obj 132 376 usbhid;
+#X msg 184 91 close;
+#X msg 184 117 reset;
+#X text 240 307 GARBAGE FOR TESTING;
+#X msg 197 155 print;
+#X text 317 72 Gravis/Destroyer Tiltpad;
+#X text 311 43 Microsoft 5-button Mouse;
+#N canvas 0 22 462 312 buttons 0;
+#X obj 99 36 inlet;
+#X obj 63 108 & 1;
+#X obj 63 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 93 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 2
+;
+#X obj 123 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+4;
+#X obj 153 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+8;
+#X obj 183 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+16;
+#X obj 223 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+32;
+#X obj 263 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 303 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+128;
+#X obj 93 108 & 2;
+#X obj 123 108 & 4;
+#X obj 153 108 & 8;
+#X obj 183 108 & 16;
+#X obj 223 108 & 32;
+#X obj 263 108 & 64;
+#X obj 303 108 & 128;
+#X connect 0 0 1 0;
+#X connect 0 0 10 0;
+#X connect 0 0 11 0;
+#X connect 0 0 12 0;
+#X connect 0 0 13 0;
+#X connect 0 0 14 0;
+#X connect 0 0 15 0;
+#X connect 0 0 16 0;
+#X connect 1 0 2 0;
+#X connect 10 0 3 0;
+#X connect 11 0 4 0;
+#X connect 12 0 5 0;
+#X connect 13 0 6 0;
+#X connect 14 0 7 0;
+#X connect 15 0 8 0;
+#X connect 16 0 9 0;
+#X restore 65 515 pd buttons test;
+#X obj 127 462 unpack float float float float;
+#X obj 44 83 metro 400;
+#X obj 46 57 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 186 499 5 0 0 0 - - -;
+#X floatatom 256 500 5 0 0 0 - - -;
+#X floatatom 336 495 5 0 0 0 - - -;
+#X msg 171 43 open 0x045e 0x0039;
+#X msg 157 13 open vendorId productId;
+#X msg 176 71 open 0x047D 0x4008;
+#X floatatom 125 496 5 0 0 0 - - -;
+#X msg 239 273 debug \$1;
+#X obj 239 251 hradio 15 1 0 10 empty empty empty 0 -6 0 8 -262144
+-1 -1 0;
+#X obj 27 441 print data;
+#N canvas 458 151 454 485 parsing 0;
+#X obj 77 6 inlet;
+#X obj 80 101 route float symbol;
+#X obj 80 190 mapping/tolist;
+#X obj 139 137 trigger symbol bang;
+#X msg 22 139 bang;
+#X obj 81 226 list trim;
+#X obj 241 312 print;
+#X obj 80 272 route path;
+#X obj 34 328 print path-------------;
+#X obj 78 31 list-abs/list-drip;
+#X obj 198 51 trigger bang bang;
+#X obj 247 89 print end---------;
+#X connect 0 0 9 0;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X connect 2 0 5 0;
+#X connect 3 0 2 0;
+#X connect 3 1 2 1;
+#X connect 4 0 2 0;
+#X connect 5 0 7 0;
+#X connect 7 0 8 0;
+#X connect 7 1 6 0;
+#X connect 9 0 1 0;
+#X connect 9 1 10 0;
+#X connect 10 0 2 1;
+#X connect 10 1 11 0;
+#X restore 226 418 pd parsing;
+#X text 8 122 how many bytes to read;
+#X msg 194 136 refresh;
+#X text 259 137 reinit and refresh device list;
+#X text 233 117 resets device (don't really know what that does tho)
+;
+#X obj 171 419 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 171 397 route open device;
+#X msg 44 104 get 4;
+#X msg 82 137 get 2;
+#X msg 212 179 descriptor;
+#X text 291 179 get descriptor;
+#X msg 219 213 descriptor 1 30 1 31 1 38;
+#X text 398 212 [descriptor page# usage# ...(;
+#X text 218 197 for writing to the device:;
+#X msg 25 208 set 2;
+#X msg 237 323 close \, open 0x045e 0x0039 \, descriptor;
+#X text 183 382 <- status outlet;
+#X text 21 383 data outlet ->;
+#X connect 0 0 8 0;
+#X connect 0 0 20 0;
+#X connect 0 1 27 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 4 0 0 0;
+#X connect 8 0 7 0;
+#X connect 8 0 17 0;
+#X connect 8 1 11 0;
+#X connect 8 2 12 0;
+#X connect 8 3 13 0;
+#X connect 9 0 28 0;
+#X connect 10 0 9 0;
+#X connect 14 0 0 0;
+#X connect 16 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 18 0;
+#X connect 23 0 0 0;
+#X connect 27 0 26 0;
+#X connect 27 1 21 0;
+#X connect 28 0 0 0;
+#X connect 29 0 0 0;
+#X connect 30 0 0 0;
+#X connect 32 0 0 0;
+#X connect 35 0 0 0;
+#X connect 36 0 0 0;
diff --git a/usbhid/usbhid.c b/usbhid/usbhid.c
new file mode 100644
index 0000000..5fc069f
--- /dev/null
+++ b/usbhid/usbhid.c
@@ -0,0 +1,782 @@
+/* --------------------------------------------------------------------------*/
+/* */
+/* Pd interface to the USB HID API using libhid, which is built on libusb */
+/* Written by Hans-Christoph Steiner <hans@at.or.at> */
+/* */
+/* Copyright (c) 2004 Hans-Christoph Steiner */
+/* */
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* See file LICENSE for further informations on licensing terms. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software Foundation, */
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/* --------------------------------------------------------------------------*/
+
+/* libhid hasn't been ported to Win32 yet */
+#ifndef _WIN32
+
+#include <usb.h>
+#include <hid.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+#include "m_pd.h"
+
+/*
+ * TODO: rename read, get, set messages so they make sense
+ * TODO: make size output work well
+ */
+
+/*
+ * BUG: for some reason it skips one of the button bits
+ */
+
+
+/*------------------------------------------------------------------------------
+ * INCLUDE KLUDGE
+ */
+
+/* NOTE: included from libusb/usbi.h. UGLY, i know, but so is libusb!
+ * this struct doesn't seem to be defined in usb.h, only prototyped
+ */
+struct usb_dev_handle {
+ int fd;
+ struct usb_bus *bus;
+ struct usb_device *device;
+ int config;
+ int interface;
+ int altsetting;
+ void *impl_info;
+};
+
+
+/*------------------------------------------------------------------------------
+ * GLOBAL VARIABLES
+ */
+
+/* count the number of instances of this object so that certain free()
+ * functions can be called only after the final instance is detroyed. */
+t_int usbhid_instance_count;
+
+#define HID_ID_MAX 32
+char *hid_id[HID_ID_MAX]; /* FIXME: 32 devices MAX */
+t_int hid_id_count;
+
+/* this array is for keeping track of whether each device has been read in
+ * each cycle */
+char usbhid_device_read_status[HID_ID_MAX];
+
+/*------------------------------------------------------------------------------
+ * CLASS DEF
+ */
+
+typedef struct _usbhid
+{
+ t_object x_obj;
+/* usbhid types */
+ HIDInterface *x_hidinterface;
+ hid_return x_hid_return;
+/* internal state */
+ unsigned short vendor_id; // idVendor for current device
+ unsigned short product_id; // idProduct for current device
+ unsigned short debug_level; // control debug messages to the console
+ t_int x_device_number;
+ t_int x_read_element_count;
+ t_int *x_read_elements;
+ t_int x_write_element_count;
+ t_int *x_write_elements;
+ t_int report_size; // size in bytes of the HID report
+/* output */
+ t_atom *output; // holder for a list of atoms to be outputted
+ t_int output_count; // number of atoms in in x->output
+ t_outlet *x_data_outlet;
+ t_outlet *x_status_outlet;
+} t_usbhid;
+
+
+/*------------------------------------------------------------------------------
+ * LOCAL DEFINES
+ */
+
+#define USBHID_MAJOR_VERSION 0
+#define USBHID_MINOR_VERSION 0
+
+static t_class *usbhid_class;
+
+/* for USB strings */
+#define STRING_BUFFER_LENGTH 256
+
+#define SEND_PACKET_LENGTH 1
+#define RECEIVE_PACKET_LENGTH 6
+#define PATH_LENGTH 3
+
+
+/*------------------------------------------------------------------------------
+ * SUPPORT FUNCTIONS
+ */
+
+/* add one new atom to the list to be outputted */
+static void add_atom_to_output(t_usbhid *x, t_atom *new_atom)
+{
+ t_atom *new_atom_list;
+
+ new_atom_list = (t_atom *)getbytes((x->output_count + 1) * sizeof(t_atom));
+ memcpy(new_atom_list, x->output, x->output_count * sizeof(t_atom));
+ freebytes(x->output, x->output_count * sizeof(t_atom));
+ x->output = new_atom_list;
+ memcpy(x->output + x->output_count, new_atom, sizeof(t_atom));
+ ++(x->output_count);
+}
+
+static void add_symbol_to_output(t_usbhid *x, t_symbol *s)
+{
+ t_atom *temp_atom = getbytes(sizeof(t_atom));
+ SETSYMBOL(temp_atom, s);
+ add_atom_to_output(x,temp_atom);
+ freebytes(temp_atom,sizeof(t_atom));
+}
+
+static void add_float_to_output(t_usbhid *x, t_float f)
+{
+ t_atom *temp_atom = getbytes(sizeof(t_atom));
+ SETFLOAT(temp_atom, f);
+ add_atom_to_output(x,temp_atom);
+ freebytes(temp_atom,sizeof(t_atom));
+}
+
+static void reset_output(t_usbhid *x)
+{
+ if(x->output)
+ {
+ freebytes(x->output, x->output_count * sizeof(t_atom));
+ x->output = NULL;
+ x->output_count = 0;
+ }
+}
+
+
+static t_int init_libhid(t_usbhid *x)
+{
+ if (! hid_is_initialised() )
+ {
+ x->x_hid_return = hid_init();
+ if(x->x_hid_return != HID_RET_SUCCESS)
+ {
+ error("[usbhid] hid_init failed with return code %d\n",
+ x->x_hid_return);
+ }
+ }
+ return(x->x_hid_return);
+}
+
+
+/*
+ * This function is used in a HIDInterfaceMatcher to iterate thru all of the
+ * HID devices on the USB bus
+ */
+static bool device_iterator (struct usb_dev_handle const* usbdev, void* custom,
+ unsigned int length)
+{
+ bool ret = false;
+ t_int i;
+ char current_dev_path[10];
+
+ /* only here to prevent the unused warning */
+ /* TODO remove */
+ length = *((unsigned long*)custom);
+
+ /* Obtain the device's full path */
+ sprintf(current_dev_path, "%s/%s", usbdev->bus->dirname, usbdev->device->filename);
+
+ /* Check if we already saw this dev */
+ for ( i = 0 ; ( hid_id[i] != NULL ) ; i++ )
+ {
+ if (!strcmp(hid_id[i], current_dev_path ) )
+ break;
+ }
+
+ /* Append device to the list if needed */
+ if (hid_id[i] == NULL)
+ {
+ hid_id[i] = (char *) malloc(strlen(usbdev->device->filename) + strlen(usbdev->bus->dirname) );
+ sprintf(hid_id[i], "%s/%s", usbdev->bus->dirname, usbdev->device->filename);
+ }
+ else /* device already seen */
+ {
+ return false;
+ }
+
+ /* Filter non HID device */
+ if ( (usbdev->device->descriptor.bDeviceClass == 0) /* Class defined at interface level */
+ && usbdev->device->config
+ && usbdev->device->config->interface->altsetting->bInterfaceClass == USB_CLASS_HID)
+ {
+
+ post("bus %s device %s: %d %d",
+ usbdev->bus->dirname,
+ usbdev->device->filename,
+ usbdev->device->descriptor.idVendor,
+ usbdev->device->descriptor.idProduct);
+ ret = true;
+ }
+
+ else
+ {
+ ret = false;
+ }
+
+
+ return ret;
+}
+
+/* -------------------------------------------------------------------------- */
+/* This function is used in a HIDInterfaceMatcher in order to match devices by
+ * serial number.
+ */
+/* static bool match_serial_number(struct usb_dev_handle* usbdev, void* custom, unsigned int length) */
+/* { */
+/* bool ret; */
+/* char* buffer = (char*)malloc(length); */
+/* usb_get_string_simple(usbdev, usb_device(usbdev)->descriptor.iSerialNumber, */
+/* buffer, length); */
+/* ret = strncmp(buffer, (char*)custom, length) == 0; */
+/* free(buffer); */
+/* return ret; */
+/* } */
+
+
+/* -------------------------------------------------------------------------- */
+/* static bool get_device_by_number(struct usb_dev_handle* usbdev, */
+/* void* custom, */
+/* unsigned int length) */
+/* { */
+/* bool ret; */
+
+
+/* return ret; */
+/* } */
+
+
+/* -------------------------------------------------------------------------- */
+static t_int* make_hid_path(t_int element_count, t_int argc, t_atom *argv)
+{
+ t_int i;
+ t_int *return_array = NULL;
+
+ post("element_count %d",element_count);
+ return_array = (t_int *) getbytes(sizeof(t_int) * element_count);
+ for(i=0; i < element_count; ++i)
+ {
+/*
+ * A usbhid path component is 32 bits, the high 16 bits identify the usage page,
+ * and the low 16 bits the item number.
+ */
+ return_array[i] =
+ (atom_getintarg(i*2,argc,argv) << 16) + atom_getintarg(i*2+1,argc,argv);
+/* TODO: print error if a symbol is found in the data list */
+ }
+ return return_array;
+}
+
+
+static t_int get_device_string(HIDInterface *hidif, char *device_string)
+{
+ int length;
+ t_int ret = 0;
+ char buffer[STRING_BUFFER_LENGTH];
+
+ if ( !hid_is_opened(hidif) )
+ return(0);
+
+ if (hidif->device->descriptor.iManufacturer) {
+ length = usb_get_string_simple(hidif->dev_handle,
+ hidif->device->descriptor.iManufacturer,
+ buffer,
+ STRING_BUFFER_LENGTH);
+ if (length > 0)
+ {
+ strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string));
+ strncat(device_string, " ",1);
+ ret = 1;
+ }
+ else
+ {
+ post("(unable to fetch manufacturer string)");
+ }
+ }
+
+ if (hidif->device->descriptor.iProduct) {
+ length = usb_get_string_simple(hidif->dev_handle,
+ hidif->device->descriptor.iProduct,
+ buffer,
+ STRING_BUFFER_LENGTH);
+ if (length > 0)
+ {
+ strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string));
+ strncat(device_string, " ",1);
+ ret = 1;
+ }
+ else
+ {
+ post("(unable to fetch product string)");
+ }
+ }
+
+ if (hidif->device->descriptor.iSerialNumber) {
+ length = usb_get_string_simple(hidif->dev_handle,
+ hidif->device->descriptor.iSerialNumber,
+ buffer,
+ STRING_BUFFER_LENGTH);
+ if (length > 0)
+ strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string));
+ else
+ post("(unable to fetch product string)");
+ }
+
+ return ret;
+}
+
+
+/*------------------------------------------------------------------------------
+ * IMPLEMENTATION
+ */
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_close(t_usbhid *x)
+{
+ if(x->debug_level) post("usbhid_close");
+ t_int ret;
+ char string_buffer[STRING_BUFFER_LENGTH];
+
+ if ( hid_is_opened(x->x_hidinterface) )
+ {
+ ret = get_device_string(x->x_hidinterface,string_buffer);
+ x->x_hid_return = hid_close(x->x_hidinterface);
+ if (x->x_hid_return == HID_RET_SUCCESS)
+ {
+ if (ret)
+ post("[usbhid]: closed %s",string_buffer);
+ else
+ post("[usbhid]: closed device");
+ reset_output(x);
+ add_float_to_output(x,0);
+ outlet_anything(x->x_status_outlet, gensym("open"),
+ x->output_count, x->output);
+ }
+ else
+ {
+ error("[usbhid] could not close %d, error #%d",x->x_device_number,x->x_hid_return);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_open(t_usbhid *x, t_symbol *vendor_id_hex, t_symbol *product_id_hex)
+{
+ if(x->debug_level) post("usbhid_open");
+ char string_buffer[STRING_BUFFER_LENGTH];
+
+ if( init_libhid(x) != HID_RET_SUCCESS ) return;
+
+/* convert hex symbols to ints */
+ x->vendor_id = (unsigned short) strtol(vendor_id_hex->s_name, NULL, 16);
+ x->product_id = (unsigned short) strtol(product_id_hex->s_name, NULL, 16);
+ if( hid_is_opened(x->x_hidinterface) )
+ {
+ if( (x->vendor_id == x->x_hidinterface->device->descriptor.idVendor) &&
+ (x->product_id == x->x_hidinterface->device->descriptor.idProduct))
+ {
+ post("[usbhid] device already opened");
+ return;
+ }
+ else
+ {
+ usbhid_close(x);
+ }
+ }
+
+ if( !hid_is_opened(x->x_hidinterface) )
+ {
+ HIDInterfaceMatcher matcher = { x->vendor_id,
+ x->product_id,
+ NULL,
+ NULL,
+ 0 };
+ x->x_hid_return = hid_force_open(x->x_hidinterface, 0, &matcher, 3);
+ if (x->x_hid_return == HID_RET_SUCCESS)
+ {
+ if (get_device_string(x->x_hidinterface,string_buffer))
+ post("[usbhid]: opened %s",string_buffer);
+ reset_output(x);
+ add_float_to_output(x,1);
+ outlet_anything(x->x_status_outlet, gensym("open"),
+ x->output_count, x->output);
+ }
+ else
+ {
+ error("[usbhid] hid_force_open failed with return code %d\n",
+ x->x_hid_return);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_set(t_usbhid *x, t_float length_arg)
+{
+ if(x->debug_level) post("usbhid_set");
+ int packet_bytes = (int)length_arg;
+ char packet[packet_bytes];
+
+ if ( !hid_is_opened(x->x_hidinterface) )
+ {
+ error("[usbhid] device not open, can't set data");
+ return;
+ }
+ x->x_hid_return = hid_set_output_report(x->x_hidinterface,
+ x->x_write_elements,
+ x->x_write_element_count,
+ packet,
+ length_arg);
+ if (x->x_hid_return != HID_RET_SUCCESS)
+ {
+ error("[usbhid] hid_get_input_report failed with return code %d\n",
+ x->x_hid_return);
+ reset_output(x);
+ add_float_to_output(x, x->x_hid_return);
+ outlet_anything(x->x_status_outlet, gensym("setError"),
+ x->output_count, x->output);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_get(t_usbhid *x, t_float length_arg)
+{
+ if(x->debug_level) post("usbhid_get");
+ int i;
+ int packet_bytes = (int)length_arg;
+ char packet[packet_bytes];
+
+ if ( !hid_is_opened(x->x_hidinterface) )
+ {
+ error("[usbhid] device not open, can't get data");
+ return;
+ }
+ x->x_hid_return = hid_get_input_report(x->x_hidinterface,
+ NULL,
+ x->x_read_element_count,
+ packet,
+ length_arg);
+ if (x->x_hid_return != HID_RET_SUCCESS)
+ {
+ error("[usbhid] hid_get_input_report failed with return code %d\n",
+ x->x_hid_return);
+ reset_output(x);
+ add_float_to_output(x, x->x_hid_return);
+ outlet_anything(x->x_status_outlet, gensym("getError"),
+ x->output_count, x->output);
+ }
+
+ reset_output(x);
+ for(i=0; i<packet_bytes; ++i)
+ add_float_to_output(x,packet[i]);
+ outlet_list(x->x_data_outlet, &s_list, x->output_count, x->output);
+ post("x->x_read_elements %d",x->x_read_elements);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* reinit libhid to get update the list of attached devices */
+static void usbhid_refresh(t_usbhid *x)
+{
+ x->x_hid_return = hid_cleanup();
+ if (x->x_hid_return != HID_RET_SUCCESS)
+ error("[usbhid] hid_cleanup failed with return code %d\n",
+ x->x_hid_return);
+ if( init_libhid(x) != HID_RET_SUCCESS ) return;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* set the HID packet for which elements to read */
+static void usbhid_set_read(t_usbhid *x, int argc, t_atom *argv)
+{
+ if(x->debug_level) post("usbhid_set_read");
+ t_int i;
+
+ x->x_read_element_count = argc / 2;
+ x->x_read_elements = make_hid_path(x->x_read_element_count, argc, argv);
+ post("x_read_element_count %d",x->x_read_element_count);
+ for(i=0;i<x->x_read_element_count;++i)
+ post("x_read_elements %d: %d",i,x->x_read_elements[i]);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* convert a list to a HID packet and set it */
+/* set the HID packet for which elements to write */
+static void usbhid_set_descriptor(t_usbhid *x, int argc, t_atom *argv)
+{
+ if(x->debug_level) post("usbhid_descriptor");
+/* int const PATH_IN[PATH_LENGTH] = { 0xffa00001, 0xffa00002, 0xffa10003 }; */
+// int const PATH_OUT[3] = { 0x00010002, 0x00010001, 0x00010030 };
+ t_int i;
+
+ x->x_write_element_count = argc / 2;
+ x->x_write_elements = make_hid_path(x->x_write_element_count, argc, argv);
+ post("x_write_element_count %d",x->x_write_element_count);
+ for(i=0;i<x->x_write_element_count;++i)
+ post("x_write_elements %d: %d",i,x->x_write_elements[i]);
+}
+
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_get_descriptor(t_usbhid *x)
+{
+ if(x->debug_level) post("usbhid_get");
+ unsigned int i = 0;
+ t_int input_size = 0;
+ t_int output_size = 0;
+ t_int feature_size = 0;
+
+ if (!hid_is_opened(x->x_hidinterface)) {
+ error("[usbget] cannot dump tree of unopened HIDinterface.");
+ }
+ else
+ {
+ post("[usbhid] parse tree of HIDInterface %s:\n", x->x_hidinterface->id);
+ reset_output(x);
+ while (HIDParse(x->x_hidinterface->hid_parser, x->x_hidinterface->hid_data)) {
+ add_symbol_to_output(x, gensym("path"));
+ switch(x->x_hidinterface->hid_data->Type)
+ {
+ case 0x80:
+ add_symbol_to_output(x, gensym("input"));
+ input_size = input_size + x->x_hidinterface->hid_data->Size;
+ break;
+ case 0x90:
+ add_symbol_to_output(x, gensym("output"));
+ output_size = output_size + x->x_hidinterface->hid_data->Size;
+ break;
+ case 0xb0:
+ add_symbol_to_output(x, gensym("feature"));
+ feature_size = feature_size + x->x_hidinterface->hid_data->Size;
+ break;
+ default: add_symbol_to_output(x, gensym("UNKNOWN_TYPE"));
+ }
+ add_float_to_output(x, x->x_hidinterface->hid_data->Size);
+ add_float_to_output(x, x->x_hidinterface->hid_data->Offset);
+ for (i = 0; i < x->x_hidinterface->hid_data->Path.Size; ++i) {
+ add_symbol_to_output(x, gensym("usage"));
+ add_float_to_output(x, x->x_hidinterface->hid_data->Path.Node[i].UPage);
+ add_float_to_output(x, x->x_hidinterface->hid_data->Path.Node[i].Usage);
+ post("page: 0x%04x\t%d\t\tusage: 0x%04x\t%d",
+ x->x_hidinterface->hid_data->Path.Node[i].UPage,
+ x->x_hidinterface->hid_data->Path.Node[i].UPage,
+ x->x_hidinterface->hid_data->Path.Node[i].Usage,
+ x->x_hidinterface->hid_data->Path.Node[i].Usage);
+ }
+ post("type: 0x%02x\n", x->x_hidinterface->hid_data->Type);
+ add_symbol_to_output(x, gensym("logical"));
+ add_float_to_output(x, x->x_hidinterface->hid_data->LogMin);
+ add_float_to_output(x, x->x_hidinterface->hid_data->LogMax);
+ }
+ add_symbol_to_output(x, gensym("totalSize"));
+ add_float_to_output(x, input_size);
+ add_float_to_output(x, output_size);
+ add_float_to_output(x, feature_size);
+ outlet_anything(x->x_status_outlet, gensym("device"),
+ x->output_count, x->output);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_descriptor(t_usbhid *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if(s == gensym("descriptor")) // get rid of unused s warning
+ {
+ if(argc)
+ usbhid_set_descriptor(x,argc,argv);
+ else
+ usbhid_get_descriptor(x);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_print(t_usbhid *x)
+{
+ if(x->debug_level) post("usbhid_print");
+ t_int i;
+ char string_buffer[STRING_BUFFER_LENGTH];
+/* t_atom event_data[3]; */
+
+ for ( i = 0 ; ( hid_id[i] != NULL ) ; i++ )
+ {
+ if( hid_id[i] != NULL )
+ post("hid_id[%d]: %s",i,hid_id[i]);
+ }
+ if(get_device_string(x->x_hidinterface,string_buffer))
+ post("%s is currently open",string_buffer);
+
+ x->x_hid_return = hid_dump_tree(stdout, x->x_hidinterface);
+ if (x->x_hid_return != HID_RET_SUCCESS) {
+ fprintf(stderr, "hid_dump_tree failed with return code %d\n", x->x_hid_return);
+ return;
+ }
+
+/* SETSYMBOL(event_data, gensym(type)); /\* type *\/ */
+/* SETSYMBOL(event_data + 1, gensym(code)); /\* code *\/ */
+/* SETSYMBOL(event_data + 2, value); /\* value *\/ */
+// outlet_list(x->x_status_outlet, &s_list,
+}
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_reset(t_usbhid *x)
+{
+ if(x->debug_level) post("usbhid_reset");
+
+ hid_reset_HIDInterface(x->x_hidinterface);
+}
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_debug(t_usbhid *x, t_float f)
+{
+ x->debug_level = f;
+
+ switch(x->debug_level)
+ {
+ case 0: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_NONE); break;
+ case 1: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_ERRORS); break;
+ case 2: hid_set_usb_debug(0);
+ hid_set_debug(HID_DEBUG_ERRORS | HID_DEBUG_WARNINGS); break;
+ case 3: hid_set_usb_debug(0);
+ hid_set_debug(HID_DEBUG_ERRORS | HID_DEBUG_WARNINGS | HID_DEBUG_NOTICES); break;
+ case 4: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_NOTRACES); break;
+ case 5: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_ALL); break;
+ default:
+ hid_set_usb_debug(x->debug_level - 5); hid_set_debug(HID_DEBUG_ALL); break;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+static void usbhid_free(t_usbhid* x)
+{
+ if(x->debug_level) post("usbhid_free");
+
+ usbhid_close(x);
+
+ freebytes(x->x_read_elements,sizeof(t_int) * x->x_read_element_count);
+ freebytes(x->x_write_elements,sizeof(t_int) * x->x_write_element_count);
+
+ if(x->debug_level)
+ post("[usbhid] freeing instance %d",usbhid_instance_count);
+ hid_delete_HIDInterface(&(x->x_hidinterface));
+ if(usbhid_instance_count <= 1)
+ {
+ post("[usbhid] freeing last instance");
+ x->x_hid_return = hid_cleanup();
+ if (x->x_hid_return != HID_RET_SUCCESS)
+ error("[usbhid] hid_cleanup failed with return code %d\n",
+ x->x_hid_return);
+ }
+
+ usbhid_instance_count--;
+}
+
+
+
+/* -------------------------------------------------------------------------- */
+static void *usbhid_new(t_float f)
+{
+ t_int i;
+ HIDInterfaceMatcher matcher;
+ t_usbhid *x = (t_usbhid *)pd_new(usbhid_class);
+
+ if(x->debug_level) post("usbhid_new");
+
+/* only display the version when the first instance is loaded */
+ if(!usbhid_instance_count)
+ post("[usbhid] %d.%d, written by Hans-Christoph Steiner <hans@eds.org>",
+ USBHID_MAJOR_VERSION, USBHID_MINOR_VERSION);
+
+ /* create anything outlet used for HID data */
+ x->x_data_outlet = outlet_new(&x->x_obj, 0);
+ x->x_status_outlet = outlet_new(&x->x_obj, 0);
+
+ /* turn off the flood of libhid debug messages by default */
+ hid_set_debug(HID_DEBUG_NONE);
+ hid_set_debug_stream(stdout);
+ hid_set_usb_debug(0);
+
+ /* data init */
+ x->output = NULL;
+ x->output_count = 0;
+ for (i = 0 ; i < HID_ID_MAX ; i++)
+ hid_id[i] = NULL;
+
+ x->x_hidinterface = hid_new_HIDInterface();
+ matcher.vendor_id = HID_ID_MATCH_ANY;
+ matcher.product_id = HID_ID_MATCH_ANY;
+ matcher.matcher_fn = device_iterator;
+
+ x->x_device_number = f;
+
+/* Open the device and save settings. If there is an error, return the object
+ * anyway, so that the inlets and outlets are created, thus not breaking the
+ * patch. */
+/* if (usbhid_open(x,f)) */
+/* error("[usbhid] device %d did not open",(t_int)f); */
+
+ usbhid_instance_count++;
+
+ return (x);
+}
+
+void usbhid_setup(void)
+{
+ usbhid_class = class_new(gensym("usbhid"),
+ (t_newmethod)usbhid_new,
+ (t_method)usbhid_free,
+ sizeof(t_usbhid),
+ CLASS_DEFAULT,
+ A_DEFFLOAT,
+ NULL);
+
+/* add inlet datatype methods */
+// class_addbang(usbhid_class,(t_method) usbhid_bang);
+
+/* add inlet message methods */
+ class_addmethod(usbhid_class,(t_method) usbhid_print,gensym("print"),0);
+ class_addmethod(usbhid_class,(t_method) usbhid_reset,gensym("reset"),0);
+ class_addmethod(usbhid_class,(t_method) usbhid_refresh,gensym("refresh"),0);
+ class_addmethod(usbhid_class,(t_method) usbhid_debug,gensym("debug"),
+ A_DEFFLOAT,0);
+ class_addmethod(usbhid_class,(t_method) usbhid_descriptor,gensym("descriptor"),
+ A_GIMME,0);
+ class_addmethod(usbhid_class,(t_method) usbhid_set,gensym("set"),
+ A_DEFFLOAT,0);
+ class_addmethod(usbhid_class,(t_method) usbhid_get,gensym("get"),
+ A_DEFFLOAT,0);
+ class_addmethod(usbhid_class,(t_method) usbhid_open,gensym("open"),
+ A_DEFSYM,A_DEFSYM,0);
+ class_addmethod(usbhid_class,(t_method) usbhid_close,gensym("close"),0);
+}
+
+#endif /* NOT _WIN32 */
diff --git a/usbhid/usbhid.libs b/usbhid/usbhid.libs
new file mode 100644
index 0000000..f4a4261
--- /dev/null
+++ b/usbhid/usbhid.libs
@@ -0,0 +1 @@
+-lusb -lhid