I am evaluating the kinetis sample code for a USB HID keyboard (dev_hid_keyboard_frdmk22f_bm_frdmk22f) and having issues sending the device and output report to control keyboard LEDs.
The dev board running the sample code enumerates fine. I have modified to device code to report button presses as keyboard events and am able to "type" with using the few buttons on the board by populate to USB HID report with ascii HID codes.
The problem I have is when I try to send a output report to the device. To send the output report I am using libusb from a UNIX host to test the device. After the device enumerates on the linux host I run the libusb application below to detach it from the host OS and try to send it an output report to change the device LEDs (see g_report_descriptor entries below)
0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) pc->kbd */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (3 */
0x91, 0x01, /* OUTPUT (Cnst,Var,Abs) filupp to byte boundary */
After sending a output report to the device from a linux host machine I do in fact receive the application registered callback, USB_App_Class_Callback(), but the data pointer for the report is NULL.
The call stack is shown below. I see the report data sent from the host on a USB sniffer. I also see it in the device inside of the _usb_khci_service_tk_dne_intr() in the call stack below inside this methods local event.buffer_ptr buffer pointer. But because USB_Control_Service() never popluates the data (sets it to a NULL pointer) it never makes it way back to the application callback.
Anyone have success in working with this sample code and sending it an output report to control the keypad LEDs?
*******************************************
***** set report call stack on device *****
*******************************************
khci_dev.c::static void _usb_khci_isr(void)
khci_dev.c::::static void _usb_khci_service_tk_dne_intr(
usb_khci_dev_state_struct_t* state_ptr)
event->setup=FALSE
usb_dev.c::usb_status _usb_device_call_service(
uint8_t type,
usb_event_struct_t* event)
usb_dev.c::_usb_device_call_service_internal(
usb_dev_state_struct_t* usb_dev_ptr,
usb_event_struct_t* event)
usb_framework.c::USB_Control_Service(
void* handle,
usb_event_struct_t* event,
void* arg)
uint8_t * data = NULL;
if (event->setup == TRUE) {
appears to copy usb packet info into data
} else {
/* class or vendor request */
usb_fw_ptr->request_notify_callback(
(usb_setup_struct_t*) usb_fw_ptr->ext_req_to_host,
&data,&size,usb_fw_ptr->request_notify_param);
which calls ...
usb_hid.c::USB_HID_Requests(
usb_setup_struct_t* setup_packet,
uint8_t * *data,
uint32_t *size,
void* arg)
keyboard.c::USB_App_Class_Callback(
uint8_t request,
uint16_t value,
uint8_t ** data,
uint32_t* size,
void* arg)
/* handle the class request */
switch(request)
{
case USB_HID_SET_REPORT_REQUEST:
for (index = 0; index < KEYBOARD_BUFF_SIZE; index++)
{ /* copy the report sent by the host */
g_keyboard.rpt_buf[index] = *(*data + index);
PROBLEM IS HERE. Since the event->setup was not set to TRUE in the above USB_Control_Service() call data is a NULL pointer.
}
break;
**********************************************
***** linux host libusb test application *****
**********************************************
// gcc -std=c99 my_libusb_dell.c -o my_libusb_dell `pkg-config libusb-1.0 --libs --cflags`
// ***** must run as root (sudo)
#include <stdbool.h>
#include <stdio.h>
#include <libusb-1.0/libusb.h>
#define VID_DELL 0x413c
#define HID_DELL 0x2107
#define VID_FREESCALE 0x15a2
#define HID_FREESCALE 0x0200
void printdev (libusb_device *dev) {
struct libusb_device_descriptor desc;
// Device Descriptor
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
printf("libusb_get_device_descriptor() failure\n");
return;
}
printf("*** Device Descriptor ***\n");
printf("\nbLength: %d\n", (int)desc.bLength);
printf("bDescriptorType: %d\n", (int)desc.bDescriptorType);
printf("bcdUSB: %d\n", (int)desc.bcdUSB);
printf("bDeviceClass: %d\n", (int)desc.bDeviceClass);
printf("bDeviceSubClass: %d\n", (int)desc.bDeviceSubClass);
printf("bDeviceProtocol: %d\n", (int)desc.bDeviceProtocol);
printf("bMaxPacketSize0: %d\n", (int)desc.bMaxPacketSize0);
printf("idVendor: %x\n", desc.idVendor);
printf("idProduct: %x\n", desc.idProduct);
printf("bcdDevice: %x\n", desc.bcdDevice);
printf("bNumConfigurations: %d\n", (int)desc.bNumConfigurations);
// Configuration Descriptor
struct libusb_config_descriptor *config;
libusb_get_config_descriptor(dev, 0, &config);
printf(" *** Configuration Descriptor ***\n");
printf(" bLength: %d\n", (int)config->bLength);
printf(" bDescriptorType: %d\n", (int)config->bDescriptorType);
printf(" wTotalLength: %d\n", (int)config->wTotalLength);
printf(" bConfigurationValue: %d\n", (int)config->bConfigurationValue);
printf(" bmAttributes: %d\n", (int)config->bmAttributes);
printf(" MaxPower: %d\n", (int)config->MaxPower);
printf(" bNumInterfaces: %d\n", (int)config->bNumInterfaces);
// Interface Descriptor (Keyboard)
const struct libusb_interface *inter;
const struct libusb_interface_descriptor *interdesc;
const struct libusb_endpoint_descriptor *epdesc;
printf(" *** Interface Descriptors ***\n");
for (int i = 0; i < (int)config->bNumInterfaces; i++) {
printf(" *** Interface Descriptor %d ***\n", i);
inter = &config->interface[i];
printf(" num_altsetting: %d\n", inter->num_altsetting);
for (int j = 0; j < inter->num_altsetting; j++) {
interdesc = &inter->altsetting[j];
printf(" bLength: %d\n", (int)interdesc->bLength);
printf(" bDescriptorType: %d\n", (int)interdesc->bDescriptorType);
printf(" bInterfaceNumber: %d\n", (int)interdesc->bInterfaceNumber);
printf(" Number of endpoints: %d\n", (int)interdesc->bNumEndpoints);
// Class code (HID code assigned by USB). 0x03
printf(" bInterfaceClass: %d\n", (int)interdesc->bInterfaceClass);
printf(" bInterfaceSubClass: %d\n", (int)interdesc->bInterfaceSubClass);
// Protocol code.
// 0 None
// 1 Keyboard
// 2 Mouse
printf(" bInterfaceProtocol: %d\n", (int)interdesc->bInterfaceProtocol);
// Endpoint Descriptor (Keyboard)
printf(" *** Endpoint Descriptors ***\n");
for (int k = 0; k < (int)interdesc->bNumEndpoints; k++) {
printf(" *** Endpoint Descriptor %d ***\n", i);
epdesc = &interdesc->endpoint[k];
printf(" bLength: %d\n", (int)epdesc->bLength);
// LIBUSB_DT_ENDPOINT = 0x05
printf(" bDescriptorType %d\n", (int)epdesc->bDescriptorType);
printf(" bEndpointAddress: %x\n", (int)epdesc->bEndpointAddress);
printf(" bmAttributes: %x\n", (int)epdesc->bmAttributes);
printf(" wMaxPacketSize: %x\n", (int)epdesc->wMaxPacketSize);
printf(" bInterval: %x\n", (int)epdesc->bInterval);
}
}
}
libusb_free_config_descriptor(config);
}
unsigned char cdata[1] =
{
0xff,
};
#define FREESCALE
#define KEYBOARD_BUFF_SIZE (8) /* report buffer size */
static unsigned char rpt_buf[KEYBOARD_BUFF_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7};
// main program
int main(int argc, char *argv[])
{
struct libusb_device **devs;
struct libusb_device_descriptor info;
struct libusb_device_handle *dev_handle;
unsigned count, i;
int rv = 0;
#if defined(FREESCALE)
uint16_t vendor_id = VID_FREESCALE;
uint16_t product_id = HID_FREESCALE;
#else
uint16_t vendor_id = VID_DELL;
uint16_t product_id = HID_DELL;
#endif
// init USB lib (this is the 1.0 lib)
if (libusb_init(NULL) < 0) {
printf("libusb_init() failure\n");
return 1;
}
// get list of devices and counts
count = libusb_get_device_list(NULL, &devs);
if (count <= 0) {
printf("libusb_get_device_list() failure\n");
return 2;
}
// walk the list, read descriptors, and dump some output from each
for (i = 0; i < count; i++) {
libusb_get_device_descriptor(devs[i], &info);
printf("VID=%04x PID=%04x\n", info.idVendor, info.idProduct);
if (info.idVendor == vendor_id && info.idProduct == product_id) {
printf("match found VID=%04x PID=%04x\n", info.idVendor, info.idProduct);
// Open the device
if (rv = libusb_open(devs[i], &dev_handle) == 0) {
// dev_handle = libusb_open_device_with_vid_pid(NULL, vendor_id, product_id);
//if (dev_handle) {
printdev(devs[i]);
// unhook the kernel's driver on the interface if necessary
#if defined(FREESCALE)
int iterface_num = 1;
#else
int iterface_num = 0;
#endif
// detatch kernal driver an obtain interface access
bool kernel_owns_interface = false;
if ((rv = libusb_kernel_driver_active(dev_handle, iterface_num)) == 1) {
printf("libusb_kernel_driver_active() - kernel driver is active\n");
if ((rv = libusb_detach_kernel_driver(dev_handle, iterface_num)) == 0) {
kernel_owns_interface = true;
}
else {
printf("libusb_detach_kernel_driver() failure\n");
}
}
else if (rv == 0) {
printf("libusb_kernel_driver_active() - kernel driver is not active\n");
}
else {
rv = -1;
printf("libusb_kernel_driver_active() failure\n");
}
if (rv != -1) {
// claim the USB HID interface
if ( (rv = libusb_claim_interface(dev_handle, iterface_num)) == 0) {
// enum libusb_endpoint_direction
// LIBUSB_ENDPOINT_IN In: device-to-host.
// LIBUSB_ENDPOINT_OUT Out: host-to-device.
// enum libusb_endpoint_direction {
// /** In: device-to-host */
// LIBUSB_ENDPOINT_IN = 0x80,
// /** Out: host-to-device */
// LIBUSB_ENDPOINT_OUT = 0x00
// };
// enum libusb_transfer_type {
// LIBUSB_TRANSFER_TYPE_CONTROL = 0,
// LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
// LIBUSB_TRANSFER_TYPE_BULK = 2,
// LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 }
// enum libusb_request_recipient {
// LIBUSB_RECIPIENT_DEVICE = 0x00,
// LIBUSB_RECIPIENT_INTERFACE = 0x01,
// LIBUSB_RECIPIENT_ENDPOINT = 0x02,
// LIBUSB_RECIPIENT_OTHER = 0x03 }
bool wait_for_exit = true;
while (wait_for_exit) {
static unsigned char ledValues = 0xff;
uint8_t bmRequestType = LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT; // 0x20 | 0x01 | 0x00
uint8_t bRequest = 0x9; // request type (SET_REPORT)
uint16_t wValue = 0x200; // value (0x2 = output report, 00 = report ID)
uint16_t wIndex = iterface_num; // 0 for keyboard HID, 1 for composite USBMS / USB Hid Keyboard
printf("rpt_buf[0-7]");
for (int i = 0; i < 7; i++) {
printf(" %x", rpt_buf[i]);
}
printf("\n");
rv = libusb_control_transfer(dev_handle,
bmRequestType, // type of write
bRequest,
wValue,
wIndex,
rpt_buf, // data packet
KEYBOARD_BUFF_SIZE, // byte count
1000); // timeout
if (rv > 0) {
printf("libusb_control_transfer() transferred %d bytes\r\n", rv);
}
else {
printf("libusb_control_transfer() failure: %x\n", rv);
}
char input = getchar();
if (input == 'x') {
wait_for_exit = false;
}
// use control ep 0 for now
// rv = libusb_interrupt_transfer...)
}
// release usb hid interface
if ( (rv = libusb_release_interface(dev_handle, iterface_num)) < 0) printf("libusb_release_interface() failure: %d\n", rv);
// re-attatch interface to kernel driver if necessary
if ( kernel_owns_interface && ((rv = libusb_attach_kernel_driver(dev_handle, iterface_num)) < 0)) printf("libusb_attach_kernel_driver() failure: %d\n", rv);
}
else {
printf("libusb_claim_interface() failure: %d\n", rv);
if ( (rv = libusb_attach_kernel_driver(dev_handle, iterface_num)) < 0) printf("libusb_attach_kernel_driver() failure: %d\n", rv);
}
}
libusb_close(dev_handle);
} else {
printf("libusb_open_device_with_vid_pid() failure\n");
rv = 1;
}
}
}
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return rv;
}
Original Attachment has been moved to: my_libusb_dell.c.zip
Hello Steveevers:
There was an issue on KSDK 1.2 that affected the USB_HID_SET_REPORT_REQUEST that is handled on USB callbacks. In newest KSDK version (1.3), this bug was fixed. You can look at these posts where this is discussed: USB_HID_SET_REPORT_REQUEST does not work correctly and Re: How can I configure an USB HID Keyboard Output Endpoint with KDS processor expert ?
In both cases, the OUPUT report could work properly!
I hope this can help you to make this request to work!
Have a nice day!
Regards,
Isaac
----------------------------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
----------------------------------------------------------------------------------------------------------------------------------------