Generic example for QNX

#include "stddef.h"
#include "stdlib.h"
#include "stdio.h"
#include "errno.h"
#include "sys/usbdi.h"
 
/* Structures */
typedef struct _buffer_data_bundle buffer_data;
struct _buffer_data_bundle{
    int length;
    void* ptr;
};
 
/* Global Variables */
struct usbd_connection* conn = NULL;
 
/* Function Declarations */
void on_usbd_insert(struct usbd_connection* conn, usbd_device_instance_t *inst);
void on_usbd_remove(struct usbd_connection* conn, usbd_device_instance_t *inst);
void urb_callback(struct usbd_urb* urb, struct usbd_pipe* pipe, void* user_data);
void signal_handler(int signo);
 
/**
* USBD Insert: Called for each device in the tree on connection, and on device insertion
* -> Attempt to attach to the matching device
* -> Set up an I/O Callback at its input endpoints
*/
void on_usbd_insert(struct usbd_connection* conn, usbd_device_instance_t *inst){
    /* Attempt to attach to the device */
    struct usbd_device* device = NULL;
    int ret = usbd_attach(conn, inst, 0, &device);
    if(ret != EOK) return;
 
    /* Parse for endpoints */
    usbd_endpoint_descriptor_t *desc;
    struct usbd_desc_node *node;
    for (int endpoint_index = 0; (desc = (usbd_endpoint_descriptor_t*) usbd_parse_descriptors(device, NULL, USB_DESC_ENDPOINT,
                                            endpoint_index, &node)) != NULL; ++endpoint_index)
    {
        /* Read the required Endpoint Info */
        /* Note this example is specifically for bulk transfer input endpoints */
        if((desc->bEndpointAddress & 0b10000000) != 0b10000000) return; //Not an input endpoint, as LSB in endpoint is not 0b1
        if((desc->bmAttributes & 0b11) != 0b10) return; //Not a bulk endpoint, as bits 0...1 are not 0b10
 
        /* Attempt to allocate space */
        void* buffer = usbd_alloc(desc->wMaxPacketSize);
        if(buffer == NULL) continue; //Failed to Allocate
 
        struct usbd_urb * urb = usbd_alloc_urb(NULL);
        if(urb == NULL){
            usbd_free(buffer);
            continue;
        }
 
        /* Open up a pipe */
        struct usbd_pipe *pipe;
        if( usbd_open_pipe(device, desc, &pipe) != EOK){
 
            usbd_free(buffer);
            usbd_free_urb(urb);
            continue;
        }
 
        /* Setup User Data for Transfer */
        buffer_data* user_data = calloc(1, sizeof(buffer_data));
        user_data->length = desc->wMaxPacketSize;
        user_data->ptr = buffer;
 
        /* Setup & Initiate Transfer */
        usbd_setup_bulk(urb, URB_DIR_IN, buffer, desc->wMaxPacketSize);
        usbd_io(urb, pipe, urb_callback, user_data, USBD_TIME_INFINITY);
 
    }
}
 
/**
* USBD Remove: Called on device removal
* -> Checks if we have an attached device
* -> Removes attached device as needed
*/
void on_usbd_remove(struct usbd_connection* conn, usbd_device_instance_t *inst){
    struct usbd_device * device;
    device = usbd_device_lookup(conn, inst);
 
    if(device != NULL){
        usbd_detach(device);
    }
}
 
/**
* URB Callback: Callback for handling URB receipt.
* *Assuming IN direction:
* -> Prints all data received in word format (AABBCCDD EEFF0011 22334455)
* -> Re-queues a URB for processing at the same pipe for the next input.
*/
void urb_callback(struct usbd_urb* urb, struct usbd_pipe* pipe, void* user_data){
    /* Get a data pointer and length */
    buffer_data * buf_data = (buffer_data *)(user_data);
    uint8_t * buffer = (uint8_t *)(buf_data->ptr);
 
    /* Print byte breakdown of received data */
    /* Note: This groups bytes by word (assuming word=4 bytes) */
    /* This is where any processing on the data would go (or you could pass it to another thread) */
    #define WORD_LEN 4
 
    printf("Receive:");
    for(int byteno = 0; byteno < buf_data->length; byteno++){
        printf("%02x", buffer[byteno]);
        if(byteno % WORD_LEN == (WORD_LEN - 1))
            printf(" ");
    }
    printf("\n");
 
    /* Prepare for re-queueing (continuous reporting) */
    usbd_setup_bulk(urb, URB_DIR_IN, ((buffer_data*)user_data)->ptr, buf_data->length);
 
    /* re-submit for I/O */
    usbd_io(urb, pipe, urb_callback, user_data, USBD_TIME_INFINITY);
}
 
/**
* Signal Handler: Quits program safely when terminated (frees memory)
*/
void signal_handler(int signo){
    if(conn != NULL) usbd_disconnect(conn); //NOTE: this also detaches associated devices and closes pipes!
    _exit(0);
}
 
/**
* Main Function: Called when ran.
* First, sets up the connection and insertion/removal callbacks
* Then, sets up signal handling so the program can stop when terminated (via ctrl+c)
* Finally, loops until signal is reached. (Alternatively: Waits for some condition to be met)
*/
int main(int argc, char* argv[]){
 
    /* Initialize USBD connection */
    usbd_device_ident_t filter = {
        USBD_CONNECT_WILDCARD,
        USBD_CONNECT_WILDCARD,
        USBD_CONNECT_WILDCARD,
        USBD_CONNECT_WILDCARD,
        USBD_CONNECT_WILDCARD
    };
 
    usbd_funcs_t functions = {
     _USBDI_NFUNCS,
      on_usbd_insert,
      on_usbd_remove,
      NULL /* Indicate that we do not need to receive any other events */
    };
 
    usbd_connect_parm_t connect_parms = {
        NULL,       /* Indicate that the default io-usb path is correct */
        USB_VERSION,
        USBD_VERSION,
        0,          /* No flags to be passed */
        argc,
        argv,
        0,          /* Default event buffer size */
        &filter,
        &functions
    };
 
    /* Attempt to start a connection via usbd_connect*/
    int error;
    struct usbd_connection *connection; /* Used to store a reference to the connection */
    error = usbd_connect(&connect_parms, &connection);
 
    if(error!=EOK) _exit(1);
 
 
    /* Signals */
    signal (SIGHUP, SIG_IGN);
    signal (SIGPWR, SIG_IGN);
    signal (SIGTERM, signal_handler);
    signal (SIGKILL, signal_handler);
 
    /* Loop until SIGTERM/SIGKILL */
    for( ; ; ) sleep(60);
}
Page updated: