USB HID устройство только запускает 1 событие

10

У меня есть мультидистанционный контроллер eDIO USB (инфракрасный приемник), который поставляется с пультом дистанционного управления ASUS PSR 2000 для веб-серфинга.

Я пытаюсь подключить удаленный контроллер к своему пи так, чтобы он получал нажатия клавиш, отправленные пультом.

Контроллер определяется как устройство HID. Вот подробности из команды lsusb -v

    Bus 001 Device 007: ID 147a:e001 Formosa Industrial Computing, Inc.
    Couldn't open device, some information will be missing
    Device Descriptor:
    bLength                18
    bDescriptorType         1
    bcdUSB               1.10
    bDeviceClass            0 (Defined at Interface level)
   bDeviceSubClass         0
   bDeviceProtocol         0
   bMaxPacketSize0         8
   idVendor           0x147a Formosa Industrial Computing, Inc.
   idProduct          0xe001
   bcdDevice            1.22
   iManufacturer           1
   iProduct                2
   iSerial                 0
   bNumConfigurations      1
  Configuration Descriptor:
  bLength                 9
  bDescriptorType         2
wTotalLength           34
bNumInterfaces          1
bConfigurationValue     1
iConfiguration          4
bmAttributes         0xa0
  (Bus Powered)
  Remote Wakeup
MaxPower              300mA
Interface Descriptor:
  bLength                 9
  bDescriptorType         4
  bInterfaceNumber        0
  bAlternateSetting       0
  bNumEndpoints           1
  bInterfaceClass         3 Human Interface Device
  bInterfaceSubClass      1 Boot Interface Subclass
  bInterfaceProtocol      2 Mouse
  iInterface              0
    HID Device Descriptor:
      bLength                 9
      bDescriptorType        33
      bcdHID               1.10
      bCountryCode            0 Not supported
      bNumDescriptors         1
      bDescriptorType        34 Report
      wDescriptorLength      20
     Report Descriptors:
       ** UNAVAILABLE **
  Endpoint Descriptor:
    bLength                 7
    bDescriptorType         5
    bEndpointAddress     0x81  EP 1 IN
    bmAttributes            3
      Transfer Type            Interrupt
      Synch Type               None
      Usage Type               Data
    wMaxPacketSize     0x0004  1x 4 bytes
    bInterval              10

Я также могу просмотреть целевое устройство в папке dev с созданным событием

    pi@raspberrypi /dev/input/by-id $ dir
    usb-Cypress_Semiconductor_eDio_USB_Multi_Remote_Controlle-event-if00

Обработчик события, связанный с ним, выглядит следующим образом, как видно из следующей команды.

pi@raspberrypi /proc/bus/input $ cat devices
I: Bus=0003 Vendor=147a Product=e001 Version=0110
N: Name="Cypress Semiconductor eDio USB Multi Remote Controlle"
P: Phys=usb-bcm2708_usb-1.2/input0
S: Sysfs=/devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.0/input/input2
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=1

Проблема заключается в том, что я пытаюсь прочитать выходные данные обработчика событий, созданного для устройства. Первое нажатие клавиши зарегистрировано, но последующие нажатия клавиш не отображаются командой CAT.

 pi@raspberrypi /dev/input $ cat event0 | xxd
 0000000: e007 9450 9476 0900 0000 0000 0000 0000  ...P.v..........

Пожалуйста, предложите мне, что я могу сделать, чтобы устройство работало. Нажатие любых клавиш после первого нажатия не возвращает ничего, если устройство не подключено повторно.

Пожалуйста, предложите, что нужно сделать, чтобы решить проблему.

Стив Ирвин
источник
Кто-нибудь что-нибудь ??? Я не знаю, что происходит с устройством. Возможно, модератор может помочь мне лучше сформулировать вопрос, если это проблема?
SteveIrwin
Вопрос хорош. Тем не менее, он довольно локализован, так что я уверен, что не многие люди имели бы такую ​​же проблему. Вас может успокоить то, что я видел нечто очень похожее, используемое говорящей лодкой Криса Уоллеса, чтобы вы могли на это взглянуть. Первое, что я бы попросил, чтобы диагностировать проблему: Вы используете концентратор с автономным питанием, потому что это может быть проблема с питанием.
Jivings
Вы пробовали без |xxd? Он буферизует вывод. Я использовал irwпакет, lircчтобы получить коды клавиш, отправленные с моего пульта.
macrojames
Пользовательский драйвер будет означать исправление ядра Linux. Более простой вариант - использовать libusb, поскольку libusb предоставляет прямой доступ к конечным точкам USB.
Ларс Пёттер

Ответы:

5

Кажется, проблема в неполных описателях USB:

  Couldn't open device, some information will be missing
  Report Descriptors:
  ** UNAVAILABLE **

Дескриптор, который можно прочитать, говорит, что это Мышь.

  bInterfaceProtocol      2 Mouse

И что будет дескриптор из 20 байтов, который описывает формат данных:

  bDescriptorType        34 Report
  wDescriptorLength      20

Но этого не хватает.

Возникла либо странная проблема с вашей конкретной комбинацией аппаратного и программного обеспечения, либо программист ленился и не реализовал дескриптор отчета, поскольку их собственный драйвер, вероятно, не нуждается в этом. Но, скорее всего, запутался драйвер, который создает устройство ввода.

Вы можете попробовать использовать libusb для чтения 4 байтов с конечной точки. Возможно, опрос работает. Или посмотрите на USB-связь, когда вы используете устройство с оригинальным драйвером. И да, это очень сложно, если у вас нет одного из дорогих USB-регистраторов. Но ядро ​​Linux поддерживает программную USB-регистрацию, и есть некоторые программные регистраторы для Windows.

Ларс Петтер
источник
4

Наконец-то у меня появилось время написать свою собственную реализацию, используя библиотеку PyUSB, которая является оберткой для Libusb.

Я размещаю код здесь. Может помочь кому-нибудь.

У меня есть еще один фрагмент кода, который создает файл конфигурации, который используется здесь. Не сопоставлены все удаленные ключи, так как они мне не нужны.

import usb.core
import usb.util
import ConfigParser 
import shlex
import subprocess
import logging

# find our device
diction={
  6402315641282315:'1',
  6402415641282415:'2',
  6402515641282515:'3',
  6402615641282615:'4',
  6402715641282715:'5',
  6402815641282815:'6',
  6402915641282915:'7',
  6403015641283015:'8',
  6403115641283115:'9',
  }



def load_config():
    dict={}
    config = ConfigParser.RawConfigParser()
    config.read('/codes/remote/remote.cfg')

    dict['vendor']=config.getint('Settings','idVendor')

    dict['product']=config.getint('Settings','idProduct')

    dict['interface']=config.getint('Settings', 'interface')

    r=config.options('Key Mappings')

    for item in r:
        if config.get('Key Mappings',item)!='': 
            dict[item]=config.get('Key Mappings',item)
            #print config.get('Key Mappings',item)
    return dict

def pyus():

    try:
        load_log()
        dict=load_config()
        join_int = lambda nums: int(''.join(str(i) for i in nums))
        #print dict

        dev = usb.core.find(idVendor=dict['vendor'], idProduct=dict['product'])
        interface=dict['interface']

        if dev is None:
            raise ValueError('Device not found')

        if dev.is_kernel_driver_active(interface) is True:
                #print "but we need to detach kernel driver"
                dev.detach_kernel_driver(interface)
        #dev.detatch_kernel_driver(interface) 
        # set the active configuration. With no arguments, the first
        # configuration will be the active one
        dev.set_configuration()

        # get an endpoint instance
        cfg = dev.get_active_configuration()
        interface_number = cfg[(0,0)].bInterfaceNumber
        alternate_setting = usb.control.get_interface(dev,interface_number)
        intf = usb.util.find_descriptor(
            cfg, bInterfaceNumber = interface_number,
            bAlternateSetting = alternate_setting
        )

        ep = usb.util.find_descriptor(
            intf,
            # match the first IN endpoint
            custom_match = \
            lambda e: \
                usb.util.endpoint_direction(e.bEndpointAddress) == \
                usb.util.ENDPOINT_IN
        )

        assert ep is not None
        #print 'packet details',ep.bEndpointAddress , ep.wMaxPacketSize

        while 1:
            try:
                data = dev.read(ep.bEndpointAddress, ep.wMaxPacketSize*2,interface,1000)
                data=data.tolist()
                key=join_int(data)
                #print "Key is " , key
                if  key in diction:

                    try:
                        args=shlex.split(dict[diction[key]])
                        #print args
                        p=subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
                        #print "Pressed key is ",diction[key]
                    except:
                        pass


            except usb.core.USBError as e:
                pass
    except:
        pass

pyus()
Стив Ирвин
источник