⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbhost.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
    
    if (length > USBTEST_MAX_CONTROL_DATA) {
        fprintf(stderr, "usbhost: internal error, control message involves too much data.\n");
        exit(EXIT_FAILURE);
    }

#if 1
    // Workaround - send additional data in the index and length fields.
    if ((length > 0) && (USB_DIR_OUT == (USB_ENDPOINT_DIR_MASK & request_type))) {
        int i;
        unsigned char*  buf = (unsigned char*) data;
        
        for (i = 0; i < length; i+= 4) {
            int this_len = length - 1;
            int ioctl_result;
            
            transfer.bRequestType   = USB_TYPE_CLASS | USB_RECIP_DEVICE;
            if (this_len > 4) {
                this_len = 4;
            }
            switch (this_len) {
              case 1: transfer.bRequest = USBTEST_CONTROL_DATA1; break;
              case 2: transfer.bRequest = USBTEST_CONTROL_DATA2; break;
              case 3: transfer.bRequest = USBTEST_CONTROL_DATA3; break;
              case 4: transfer.bRequest = USBTEST_CONTROL_DATA4; break;
              default:
                fprintf(stderr, "usbhost: internal error, confusion about transfer length.\n");
                exit(EXIT_FAILURE);
            }
            transfer.wValue     = (buf[i]   << 8) | buf[i+1];   // Possible read beyond end of buffer,
            transfer.wIndex     = (buf[i+2] << 8) | buf[i+3];   // but not worth worrying about.
            transfer.wLength    = 0;
            transfer.timeout    = 10 * 1000; // ten seconds, the target should always accept data faster than this.
            transfer.data       = NULL;

            // This is too strict, deciding what to do about errors should be
            // handled by higher-level code. However it will do for now.
            ioctl_result = ioctl(fd, USBDEVFS_CONTROL, &transfer);
            if (0 != ioctl_result) {
                fprintf(stderr, "usbhost: error, failed to send control message (data) to target.\n");
                exit(EXIT_FAILURE);
            }
        }
        // There is no more data to be transferred.
        length = 0;
    }
#endif    
    transfer.bRequestType       = request_type;
    transfer.bRequest           = request;
    transfer.wValue             = value;
    transfer.wIndex             = index;
    transfer.wLength            = length;
    transfer.timeout            = 10000;
    transfer.data               = data;

    result = ioctl(fd, USBDEVFS_CONTROL, &transfer);
    return result;
}

// A variant of the above which can be called when the target should always respond
// correctly. This can be used for class control messages.
static int
usb_reliable_control_message(int fd, int request_type, int request, int value, int index, int length, void* data)
{
    int result = usb_control_message(fd, request_type, request, value, index, length, data);
    if (-1 == result) {
        fprintf(stderr, "usbhost: error, failed to send control message %02x to target.\n", request);
        fprintf(stderr, "       : errno %d (%s)\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    return result;
}

    
// Either send or receive a single bulk message. The top bit of the endpoint
// number indicates the direction.
static int
usb_bulk_message(int fd, int endpoint, unsigned char* buffer, int length)
{
    struct  usbdevfs_bulktransfer    transfer;
    int     result;
    
    transfer.ep         = endpoint;
    transfer.len        = length;
    transfer.timeout    = 60 * 60 * 1000;
    // An hour. These operations should not time out because that
    // leaves the system in a confused state. Instead there is
    // higher-level recovery code that should ensure the operation
    // really does complete, and the return value here is used
    // by the calling code to determine whether the operation
    // was successful or whether there was an error and the recovery
    // code was invoked.
    transfer.data       = buffer;
    errno               = 0;
    result = ioctl(fd, USBDEVFS_BULK, &transfer);
    return result;
}


// Synchronise with the target. This can be used after the host has sent a request that
// may take a bit of time, e.g. it may involve waking up a thread. The host will send
// synch requests at regular intervals, until the target is ready.
//
// The limit argument can be used to avoid locking up. -1 means loop forever, otherwise
// it means that many iterations of 100ms apiece.
static int
usb_sync(int fd, int limit)
{
    unsigned char   buf[1];
    struct timespec delay;
    int             loops   = 0;
    int             result  = 0;

    VERBOSE(2, "Synchronizing with target\n");
    
    while (1) {
        buf[0]  = 0;
        usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_SYNCH, 0, 0, 1, buf);
        if (buf[0]) {
            result = 1;
            break;
        } else {
            if ((-1 != limit) && (++loops > limit)) {
                break;
            } else {
                VERBOSE(3, "Not yet synchronized, sleeping\n");
                delay.tv_sec    = 0;
                delay.tv_nsec   = 100000000;    // 100 ms
                nanosleep(&delay, NULL);
            }
        }
    }
    VERBOSE(2, "%s\n", result ? "Synchronized" : "Not synchronized");
    return result;
}

// Abort the target. Things seem to be completely messed up and there is no easy
// way to restore sanity to both target and host.
static void
usb_abort(int fd)
{
    VERBOSE(2, "Target-side abort operation invoked\n");
    usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_ABORT, 0, 0, 0, (void*)0);
}

/*}}}*/
/*{{{  Initialise endpoints                                     */

// ----------------------------------------------------------------------------
// On power-up some endpoints may not be in a sensible state. For example,
// with the SA11x0 the hardware may start accepting bulk OUT transfers
// before the target-side software has started a receive operation,
// so if the host sends a bulk packet before the target is ready then
// things get messy. This is especially troublesome if the target-side
// attempts any diagnostic output because of verbosity.
//
// This code loops through the various endpoints and makes sure that
// they are all in a reasonable state, before any real tests get run
// That means known hardware flaws do not show up as test failures,
// but of course they are still documented and application software
// will have to do the right thing.

static void
usb_initialise_control_endpoint(int min_size, int max_size)
{
    // At this time there are no known problems on any hardware
    // that would need to be addressed
}

static void
usb_initialise_isochronous_in_endpoint(int number, int min_size, int max_size)
{
    // At this time there are no known problems on any hardware
    // that would need to be addressed
}

static void
usb_initialise_isochronous_out_endpoint(int number, int min_size, int max_size)
{
    // At this time there are no known problems on any hardware
    // that would need to be addressed
}

static void
usb_initialise_bulk_in_endpoint(int number, int min_size, int max_size, int padding)
{
    // At this time there are no known problems on any hardware
    // that would need to be addressed
}

static void
usb_initialise_bulk_out_endpoint(int number, int min_size, int max_size)
{
    unsigned char buf[1];

    // On the SA1110 the hardware comes up with a bogus default value,
    // causing the hardware to accept packets before the software has
    // set up DMA or in any way prepared for incoming data. This is
    // a problem. It is worked around by making the target receive
    // a single packet, sending that packet, and then performing a
    // sync.
    VERBOSE(2, "Performing bulk OUT initialization on endpoint %d\n", number);
    
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,
                                 USBTEST_INIT_BULK_OUT, number, 0, 0, (void*) 0);
    usb_bulk_message(usb_master_fd, number, buf, 1);
    usb_sync(usb_master_fd, 10);
}

static void
usb_initialise_interrupt_in_endpoint(int number, int min_size, int max_size)
{
    // At this time there are no known problems on any hardware
    // that would need to be addressed
}

static void
usb_initialise_interrupt_out_endpoint(int number, int min_size, int max_size)
{
    // At this time there are no known problems on any hardware
    // that would need to be addressed
}

/*}}}*/
/*{{{  Host/target common code                                  */

#define HOST
#include "../tests/common.c"

/*}}}*/
/*{{{  The test cases themselves                                */

/*{{{  UsbTest definition                                       */

// ----------------------------------------------------------------------------
// All the data associated with a single test.

typedef struct UsbTest {

    // A "unique" identifier to make verbose output easier to understand.
    int                 id;          
    // Which file descriptor should be used to access USB.
    int                 fd;
    
    // Which test should be run.
    usbtest             which_test;

    // Test-specific details.
    union {
        UsbTest_Bulk        bulk;
        UsbTest_ControlIn   control_in;
    } test_params;

    // How to recover from any problems. Specifically, what kind of message
    // could the target send or receive that would unlock the thread on this
    // side.
    UsbTest_Recovery    recovery;

    int                 result_pass;
    char                result_message[USBTEST_MAX_MESSAGE];
    unsigned char       buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];
} UsbTest;

// Reset the information in a given test. This is used by the pool allocation
// code. The data union is left alone, filling in the appropriate union
// member is left to other code.
static void
reset_usbtest(UsbTest* test)
{
    static int next_id = 1;
    test->id                    = next_id++;
    test->which_test            = usbtest_invalid;
    usbtest_recovery_reset(&(test->recovery));
    test->result_pass           = 0;
    test->result_message[0]     = '\0';
}

/*}}}*/
/*{{{  bulk OUT                                                 */

static void
run_test_bulk_out(UsbTest* test)
{
    unsigned char*  buf     = test->buffer;
    int             i;

    VERBOSE(1, "Starting test %d, bulk OUT on endpoint %d\n", test->id, test->test_params.bulk.endpoint);
    
    for (i = 0; i < test->test_params.bulk.number_packets; i++) {
        int transferred;
        int packet_size = test->test_params.bulk.tx_size;

        test->recovery.endpoint     = test->test_params.bulk.endpoint;
        test->recovery.protocol     = USB_ENDPOINT_XFER_BULK;
        test->recovery.size         = packet_size;
        
        usbtest_fill_buffer(&(test->test_params.bulk.data), buf, packet_size);
        if (verbose < 3) {
            VERBOSE(2, "Bulk OUT test %d: iteration %d, packet size %d\n", test->id, i, packet_size);
        } else {
            // Output the first 32 bytes of data as well.
            char msg[256];
            int  index;
            int  j;
            index = snprintf(msg, 255, "Bulk OUT test %d: iteration %d, packet size %d\n    Data %s:",
                             test->id, i, packet_size,
                             (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : "");

            for (j = 0; ((j + 3) < packet_size) && (j < 32); j+= 4) {
                index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -