The device is configured to send
and receive 32 byte reports.  The designer of the USB project has code
written in Windows Pascal (Delphi?) to control the device.  The code
is a rework from the code generated by EasyHID and is a USB controlled
car radio.  Here is my output of lsusb:

------------------------------------------------------------
llamabox hqct # lsusb -d 04d8:000a -vvv

Bus 001 Device 002: ID 04d8:000a Microchip Technology, Inc.
Device Descriptor:
 bLength                18
 bDescriptorType         1
 bcdUSB               2.00
 bDeviceClass            0 (Defined at Interface level)
 bDeviceSubClass         0
 bDeviceProtocol         0
 bMaxPacketSize0         8
 idVendor           0x04d8 Microchip Technology, Inc.
 idProduct          0x000a
 bcdDevice            0.01
 iManufacturer           1 Datalex
 iProduct                2 Car-Radio
 iSerial                 0
 bNumConfigurations      1
 Configuration Descriptor:
   bLength                 9
   bDescriptorType         2
   wTotalLength           41
   bNumInterfaces          1
   bConfigurationValue     1
   iConfiguration          0
   bmAttributes         0xa0
     Remote Wakeup
   MaxPower              100mA
   Interface Descriptor:
     bLength                 9
     bDescriptorType         4
     bInterfaceNumber        0
     bAlternateSetting       0
     bNumEndpoints           2
     bInterfaceClass         3 Human Interface Devices
     bInterfaceSubClass      0 No Subclass
     bInterfaceProtocol      0 None
     iInterface              0
       HID Device Descriptor:
         bLength                 9
         bDescriptorType        33
         bcdHID               1.01
         bCountryCode            0 Not supported
         bNumDescriptors         1
         bDescriptorType        34 Report
         wDescriptorLength      47
         Report Descriptor: (length is 47)
           Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
                           (null)
           Item(Local ): Usage, data= [ 0x01 ] 1
                           (null)
           Item(Main  ): Collection, data= [ 0x01 ] 1
                           Application
           Item(Local ): Usage, data= [ 0x03 ] 3
                           (null)
           Item(Global): Logical Minimum, data= [ 0x00 ] 0
           Item(Global): Logical Maximum, data= [ 0x00 0xff ] 65280
           Item(Global): Report Size, data= [ 0x08 ] 8
           Item(Global): Report Count, data= [ 0x20 ] 32
           Item(Main  ): Input, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position
Non_Volatile Bitfield
           Item(Local ): Usage, data= [ 0x04 ] 4
                           (null)
           Item(Global): Logical Minimum, data= [ 0x00 ] 0
           Item(Global): Logical Maximum, data= [ 0x00 0xff ] 65280
           Item(Global): Report Size, data= [ 0x08 ] 8
           Item(Global): Report Count, data= [ 0x20 ] 32
           Item(Main  ): Output, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position
Non_Volatile Bitfield
           Item(Local ): Usage, data= [ 0x05 ] 5
                           (null)
           Item(Global): Logical Minimum, data= [ 0x00 ] 0
           Item(Global): Logical Maximum, data= [ 0x00 0xff ] 65280
           Item(Global): Report Size, data= [ 0x08 ] 8
           Item(Global): Report Count, data= [ 0x02 ] 2
           Item(Main  ): Feature, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position
Non_Volatile Bitfield
           Item(Main  ): End Collection, data=none
     Endpoint Descriptor:
       bLength                 7
       bDescriptorType         5
       bEndpointAddress     0x81  EP 1 IN
       bmAttributes            3
         Transfer Type            Interrupt
         Synch Type               None
         Usage Type               Data
       wMaxPacketSize     0x0040  1x 64 bytes
       bInterval               1
     Endpoint Descriptor:
       bLength                 7
       bDescriptorType         5
       bEndpointAddress     0x01  EP 1 OUT
       bmAttributes            3
         Transfer Type            Interrupt
         Synch Type               None
         Usage Type               Data
       wMaxPacketSize     0x0040  1x 64 bytes
       bInterval               1
------------------------------------------------------------

As you can see, the device is rather simple. 3 reports (input, output,
and feature) and contains two interrupt endpoints.

I tried writing a kernel module based around usb-skel.c. I changed the
skeleton to write to the interrupt endpoints instead of using bulk
transfer since that is not supported by the PIC.  I was able to
noticeably change the state of the device, but the results varied and
I haven't been able to alter the device like this since then.

I then tried using libhid, but it seems like the library is immature
and simply not the solution I was hoping for.  While using that
solution I tried several paths, rebooting between each one:
{ 0xffa00001, 0xffa00003 }
{ 0xffa00003 }
{ 0xffa00001, 0xffa00004 }
{ 0xffa00004 }
{ 0xffa10001, 0xffa00003 }
I have even tried using three different functions for writing while
using the libhid approach: hid_set_output_report(),
usb_interrupt_write(), and hid_interrupt_write().

So, that brings us to the HIDDEV.  It took me a long time to make
sense of hiddev.txt, but I'm pretty sure I understand it.  I wrote a
simple demo application which I have included below.  The program does
not seem to affect the unit at all. I can hear some crosstalk from the
device's headphone jack while the report is being sent to the device
though.

Here is the source, it isn't the best but it should work:

------------------------------------------------------------
// Simple HQCT test program using HIDDEV

#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <asm/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/hiddev.h>

struct hiddev_usage_ref   uref_out;    // The output usage ref
struct hiddev_report_info rinfo_out;  // The output report info
int found_out = 0;                        // 1 = found an output, 0 =
no output found

unsigned char go_am[] =
"\x18\x30\x40\x0f\x9f\x01\x00\x30\x50\x50\x74\x6f\x6a\x00\x03\x03\x10\x0A\x0c\x01\x01\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00";
// Control string

static void showReports(int fd, unsigned report_type)
{
   struct hiddev_report_info rinfo;
   struct hiddev_field_info finfo;
   struct hiddev_usage_ref uref;
   int i, j, ret;

   rinfo.report_type = report_type;
   rinfo.report_id = HID_REPORT_ID_FIRST;
   ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);

   // Get Reports
   while (ret >= 0)
   {
       printf("HIDIOCGREPORTINFO: report_id=0x%X (%u fields)\n",
           rinfo.report_id, rinfo.num_fields);

       // Copy the output report
       if( report_type == HID_REPORT_TYPE_OUTPUT ) {
           memcpy(&rinfo_out, &rinfo, sizeof(rinfo));
           found_out = 1;
       }

       // Get Fields
       for (i = 0; i < rinfo.num_fields; i++)
       {
           finfo.report_type = rinfo.report_type;
           finfo.report_id   = rinfo.report_id;
           finfo.field_index = i;
           ioctl(fd, HIDIOCGFIELDINFO, &finfo);

printf("HIDIOCGFIELDINFO: field_index=%u maxusage=%u flags=0x%X\n"
               "\tphysical=0x%X logical=0x%X application=0x%X\n"
               "\tlogical_minimum=%d,maximum=%d
physical_minimum=%d,maximum=%d\n",
               finfo.field_index, finfo.maxusage, finfo.flags,
               finfo.physical, finfo.logical, finfo.application,
               finfo.logical_minimum,  finfo.logical_maximum,
               finfo.physical_minimum, finfo.physical_maximum);


           // Get usages
           for (j = 0; j < finfo.maxusage; j++)
           {
               uref.report_type = finfo.report_type;
               uref.report_id   = finfo.report_id;
               uref.field_index = i;
               uref.usage_index = j;
               ioctl(fd, HIDIOCGUCODE, &uref);
               ioctl(fd, HIDIOCGUSAGE, &uref);

printf(" >> usage_index=%u usage_code=0x%X () value=0x%X\n",
                   uref.usage_index,
                   uref.usage_code,
                   uref.value);

               // First output usage: grab it.
               if(uref.report_type == HID_REPORT_TYPE_OUTPUT && j==0) {
                   memcpy(&uref_out, &uref, sizeof(uref));
               }

           }

       }
       printf("\n");

       rinfo.report_id |= HID_REPORT_ID_NEXT;
       ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
   }
}

int main (int argc, char **argv) {

   int fd = -1;
   int i;

   if (argc != 2) {
       fprintf(stderr, "usage: %s hiddevice - probably
/dev/usb/hiddev0\n", argv[0]);
       exit(1);
   }
   if ((fd = open(argv[1], O_RDONLY)) < 0) {
       perror("hiddev open");
       exit(1);
   }

   printf("\n*** INPUT:\n"); showReports(fd, HID_REPORT_TYPE_INPUT);
   printf("\n*** OUTPUT:\n"); showReports(fd, HID_REPORT_TYPE_OUTPUT);
   printf("\n*** FEATURE:\n"); showReports(fd, HID_REPORT_TYPE_FEATURE);

   if( found_out ) {
       printf("The output report was found, trying to send: \n");

       printf("HIDIOCGREPORTINFO: report_id=0x%X (%u fields)\n",
               rinfo_out.report_id, rinfo_out.num_fields);

       // There are 32 usages in and out
       for(i = 0; i < 32; i++) {
           uref_out.usage_index = i;
           uref_out.value = go_am[i];

           printf(" << usage_index=%u usage_code=0x%X () value=0x%X\n",
               uref_out.usage_index,
               uref_out.usage_code,
               uref_out.value);

           if( ioctl(fd,HIDIOCSUSAGE, &uref_out) != 0 ) {
               perror(" !! SUSAGE failed. ");
           }
       }

       printf(" << sending report ...\n");
       if( ioctl(fd,HIDIOCSREPORT,&rinfo_out) != 0 ) {
           perror(" !! SREPORT ");
       } else {
           printf(" << report sent.\n");
       }
   } else {
       printf(" !! Could not find HQCT Radio.\n");
   }

   close(fd);

   return 0;
}

------------------------------------------------------------

Here is what happens: The program is run and the report is sent in a
split second. The second time I run the program, the output from the
previous run is still contained in the output report (since it is read
by showReports).  However, the call to HIDIOCSREPORT takes around
5-8seconds instead of < 1s like the first run.  All successive runs
exhibit this behavior. Oh yeah, and the radio does not respond to my
report at all.  I have even tried changing HID_REPORT_TYPE_OUTPUT to
HID_REPORT_TYPE_INPUT.

Here are my questions: Am I using the best method? Is there a simpler
way to do this? Is my demo program written correctly? And finally, if
everything seems fine, what could the problem possibly be (besides a
faulty command string)? I have included the output from two
consecutive runs to my demo program below.

Thanks,
Paul Giblock


------------------------------------------------------------
Hi, I have not seen any other replies. That usually means no one understands your question.

Everything looks ok to me, but are you running as a low speed device? If so, you are out of spec. Windows does not care, but there may be some tests in Linux. If you are a low speed device, the maximum packet size is 8 bytes. USB spec designers realized that every low speed bit consumes 8 high speed bits, so they only allowed a max of 8 byte packets.

Regards ~Steve






-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to