Fwd: Raw hid gadget

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



For some odd reason, my emails are not getting through to the list.
Even after removing the HTML parts.

Hopefully this makes it.

Rogan


---------- Forwarded message ----------
From: Rogan Dawes <rogan@xxxxxxxxxxxx>
Date: Mon, Jan 9, 2017 at 10:24 PM
Subject: Fwd: Raw hid gadget
To: linux-usb@xxxxxxxxxxxxxxx, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>

Sigh! This got bounced because of HTML parts.

Another question that arises, though:

What sort of performance can I expect writing to and reading from a
RAW HID gadget, configured using that descriptor?

My understanding is that I should be able to get 64kBps, based on a
64-byte packet, and a 1000 packet per second limit.

With my current code, and a Windows host, I am only able to get
approximately 1kBps :-(

Here is the code I am using on the Linux side to "pipe" a socket over
the raw HID device, chunked up into 63-byte packets:

#!/usr/bin/env python3

import selectors
import socket
import os
import fcntl

def set_blocking(fd, blocking):
    flag = fcntl.fcntl(fd, fcntl.F_GETFL)
    if blocking == False:
        fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
    else:
        fcntl.fcntl(fd, fcntl.F_SETFL, flag & ~os.O_NONBLOCK)

def accept(sock, mask):
    conn, addr = sock.accept()  # Should be ready
    print('accepted', conn, 'from', addr)
    global connection
    connection = conn
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read_socket)

def read_socket(conn, mask):
    global connection
    data = conn.recv(63)  # Should be ready
    if data:
        print('< ', repr(data))
        set_blocking(hidg.fileno(), True)
        hidg.write(bytes([len(data)])+data+bytes(64-len(data)-1))
        hidg.flush()
        set_blocking(hidg.fileno(), False)
    else:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()
        connection = None

def read_hid(conn, mask):
    data = hidg.read(64)  # Should be ready
    if data:
        if data[0:1] != b'\0':
            print('> ', repr(data[1:]))
            data = data[1:data[0]]
            if connection != None:
                connection.send(data)  # Hope it won't block
    else:
        print('closing', connection)
        sel.unregister(connection)
        connection.close()
        sel.unregister(hidg)
        hidg.close()

sel = selectors.DefaultSelector()
connection = None

hidg = open('/dev/hidg1', 'r+b')
set_blocking(hidg.fileno(), False)

sel.register(hidg, selectors.EVENT_READ, read_hid)

sock = socket.socket()
sock.bind(('localhost', 8089))
sock.listen(1)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)

The Windows side code is at
https://github.com/SensePost/USaBUSe/powershell/, most notably
read_exec.ps1 which is normally "typed out" via the gadget keyboard,
followed by spawn.ps1 which is normally sent over the raw hid
interface.

Any insight you can offer will be much appreciated!

Regards,

Rogan



---------- Forwarded message ----------
From: Rogan Dawes <rogan@xxxxxxxxxxxx>
Date: Mon, Jan 9, 2017 at 7:51 AM
Subject: Re: Raw hid gadget
To: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Cc: linux-usb@xxxxxxxxxxxxxxx


Hi Alan,

My responses are inline.

On Sun, Jan 8, 2017 at 12:15 AM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
> On Sat, 7 Jan 2017, Rogan Dawes wrote:
>
>> Hi Alan,
>>
>> Thanks for the response. I have not read hiddev.txt, so that explains
>> the incorrect expectations. If I may ask, why is the value a 4-byte
>> field? Is that just to round it to 8 bytes?
>
> Probably because the original programmers needed to accomodate the data
> that could appear in any report.  Since data fields can be as large as
> 32 bits, that means the field has to be 4 bytes long.
>

Makes sense, I guess ;-)

>> The "English" version of the descriptor is as follows, from the
>> original LUFA source:
>>
>> HID_DESCRIPTOR_VENDOR(0x00, 0x01, 0x02, 0x03, GENERIC_REPORT_SIZE) /*
>> GENERIC_REPORT_SIZE == 64 */
>>
>> And parsed using http://eleccelerator.com/usbdescreqparser/, translates to:
>>
>> 0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
>> 0x09, 0x01,        // Usage (0x01)
>
> Hmmm.  Is there any reason for this item?

Not specifically, it is just copy and paste from the sample code ;-)

> So your device produces (and consumes) reports containing 64 8-bit
> values.  Presumably in a 64-byte data packet.

Yes, it is my understanding that this is the largest packet size
allowed for a generic hid interface.

>> So I apparently need to extract just the 5th byte from the packet, and
>> discard the rest. Excellent!
>
> (Not from the _packet_, but from the data you receive over the rawhid
> interface.)
>
> Well, that's if you want to read just the first value.  If you want to
> read the second value, you have to extract the 13th byte, if you want
> to read the third value, you have to extract the 21st byte, and so on.

Gotcha!

> This raises the question of how many of the values in the report are
> real.  In your first example, for instance, there must have been 64
> values but only 4 of them were real.  How are you going to tell where
> the real data ends in each report?

I use the first byte as a length indicator, and the remaining 63 bytes as data.

Rogan
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux