Class: Uhid

Inherits:
Object
  • Object
show all
Defined in:
lib/uhid.rb

Overview

Linux UHID class.

This class allows the creation of virtual USB HID devices on Linux using the ‘uhid` kernel module.

Author:

  • David P. Sugar (r4gus)

Constant Summary collapse

RD_FIDO =

FIDO2/U2F USB report descriptor

"\x06\xd0\xf1\x09\x01\xa1\x01\x09"\
"\x20\x15\x00\x26\xff\x00\x75\x08"\
"\x95\x40\x81\x02\x09\x21\x15\x00"\
"\x26\xff\x00\x75\x08\x95\x40\x91"\
"\x02\xc0".force_encoding("BINARY")

Instance Method Summary collapse

Constructor Details

#initialize(name = "ruby-fido", rd = RD_FIDO, vendor = 0x15d9, product = 0x0a37, path = "/dev/uhid") ⇒ Uhid

Create a new virtual HID device.

Parameters:

  • name (String) (defaults to: "ruby-fido")

    the name of the device.

  • rd (String) (defaults to: RD_FIDO)

    ‘BINARY` encoded report descriptor.

  • vendor (Integer) (defaults to: 0x15d9)

    vendor ID.

  • product (Integer) (defaults to: 0x0a37)

    product ID.

  • path (String) (defaults to: "/dev/uhid")

    the file path (usually ‘/dev/uhid`).



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/uhid.rb', line 22

def initialize(
  name = "ruby-fido", 
  rd = RD_FIDO, 
  vendor = 0x15d9, 
  product = 0x0a37, 
  path = "/dev/uhid"
)
  @file = File.open(path, "r+", File::NONBLOCK)
  ObjectSpace.define_finalizer(self, method(:finalize))
  self.create(name, vendor, product, rd)
end

Instance Method Details

#readObject

Read data from the host.

All returned hashes contain the type key that specifies the type of the received packet. Valid types are: START, STOP, OPEN, CLOSE, OUTPUT. Only OUTPUT Hashes contain a data field that holds the data received by the host.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'ext/uhid/uhid.c', line 123

static VALUE
cuhid_read_data(VALUE self)
{
    ID file_var = rb_intern("@file");
    VALUE file = rb_ivar_get(self, file_var);
    Check_Type(file, T_FILE);
    VALUE file_fileno = rb_funcall(file, rb_intern("fileno"), 0);
    int fd = NUM2INT(file_fileno);

    struct uhid_event ev; 
    
    memset(&ev, 0, sizeof(ev));
    ssize_t ret = read(fd, &ev, sizeof(ev));

    if (ret == -1) { // EAGAIN
        return Qnil;
    }
    
    VALUE h = rb_hash_new();
    switch (ev.type) {
    case UHID_START:
        rb_hash_aset(h, rb_str_new_cstr("type"), rb_str_new_cstr("START"));
        return h;
    case UHID_STOP:
        rb_hash_aset(h, rb_str_new_cstr("type"), rb_str_new_cstr("STOP"));
        return h;
    case UHID_OPEN:
        rb_hash_aset(h, rb_str_new_cstr("type"), rb_str_new_cstr("OPEN"));
        return h;
    case UHID_CLOSE:
        rb_hash_aset(h, rb_str_new_cstr("type"), rb_str_new_cstr("CLOSE"));
        return h;
    case UHID_OUTPUT:
        rb_hash_aset(h, rb_str_new_cstr("type"), rb_str_new_cstr("OUTPUT"));
        rb_hash_aset(h, rb_str_new_cstr("data"), rb_str_new((const char *) ev.u.output.data, ev.u.output.size));
        return h;
    default:
        return Qnil;
    }
}

#write(data) ⇒ Object

Write the given data to the host.

Make sure you send the data in a format, expected by the host, e.g. in 64 byte chunks.

Parameters:

  • data (String)

    the data to be sent to the host.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'ext/uhid/uhid.c', line 84

static VALUE
cuhid_write_data(VALUE self, VALUE data)
{
    const char* d = RSTRING_PTR(StringValue(data));
    size_t l = RSTRING_LEN(StringValue(data));
    size_t size = l;
    if (size > UHID_DATA_MAX) {
        size = UHID_DATA_MAX;
    }

    struct uhid_event ev; 
    
    memset(&ev, 0, sizeof(ev));
    ev.type = UHID_INPUT2;
    memcpy(ev.u.input2.data, d, size);
    ev.u.input2.size = size;

    ID file_var = rb_intern("@file");
    VALUE file = rb_ivar_get(self, file_var);
    Check_Type(file, T_FILE);
    VALUE file_fileno = rb_funcall(file, rb_intern("fileno"), 0);
    int fd = NUM2INT(file_fileno);

    cuhid_write(fd, &ev);
    
    // We the number of processed bytes
    return INT2NUM(size);
}