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

📄 usbhost.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*{{{  Banner                                                   *///=================================================================////        host.c////        USB testing - host-side////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):     bartv// Date:          2001-07-04//####DESCRIPTIONEND####//==========================================================================// The overall architecture is as follows.//// The target hardware runs a special application which provides a// particular type of USB application, "Red Hat eCos USB testing".// This will not be recognised by any device driver, so the Linux// kernel will pretty much ignore the device (other host OS's are not// considered at this time).//// This program is the only supported way to interact with that service.// It acts as an extended Tcl interpreter, providing a number of new// Tcl commands for interacting with the target. All test cases can// then be written as Tcl scripts which invoke a series of these commands.// These Tcl commands operate essentially though the LINUX usb devfs// service which allows ordinary application code to perform USB operations// via ioctl()'s./*}}}*//*{{{  #include's                                               */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <limits.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <time.h>#include <pthread.h>#include <semaphore.h>// Avoid compatibility problems with Tcl 8.4 vs. earlier#define USE_NON_CONST#include <tcl.h>#include <linux/usb.h>#include <linux/usbdevice_fs.h>#include "../tests/protocol.h"/*}}}*//*{{{  Statics                                                  */// ----------------------------------------------------------------------------// Statics.// Has the current batch of tests actually terminated? This flag is// checked by the various test handlers at appropriate intervals, and// helps to handle the case where one of the side has terminated early// because an error has been detected.static int          current_tests_terminated = 0;// The next local thread to be allocated for testing. This variable can also// be used to find out how many threads are involved in the current test.// This counter should always be reset to 0 at the end of every test run.static int          local_thread_count      = 0;// A similar counter for remote threads.static int          remote_thread_count     = 0;// A file handle for manipulating the USB device at a low levelstatic int          usb_master_fd  = -1;/*}}}*//*{{{  Logging                                                  */// ----------------------------------------------------------------------------// The user can provide one or more -V/--verbose arguments to increase// the amount of output generated.static int verbose = 0;#define VERBOSE(_level_, _format_, _args_...)   \    do {                                        \        if (verbose >= _level_) {               \            printf(_format_, ## _args_);        \        }                                       \    } while (0);/*}}}*//*{{{  Low-level USB access                                     */// ----------------------------------------------------------------------------// Low-level access to a USB device.//// The various ioctl() calls require a file handle which corresponds to one// of the /proc/bus/usb/<abc>/<def> entries. <abc> is a bus number,// typically 001 or 001, and <def> is a device number on that bus,// e.g. 003. Figuring out <abc> and <def> requires scanning// /proc/bus/usb/devices, which is a somewhat complicated text file.//// This is all somewhat vulnerable to incompatible changes in the// Linux kernel, specifically the implementation of the /proc/bus/usb.// An alternative approach would be to write a new Linux device driver// and interact with that, but that approach is vulnerable to any// internal kernel API changes affecting USB device drivers.// How to access USB devices from userland#define USB_ROOT        "/proc/bus/usb/"// How to identify the eCos test case#define PRODUCT_STRING    "Red Hat eCos USB test"// Scan through /proc/bus/usb/devices looking for an entry that// matches what we are after, specifically a line//   S:  Product=Red Hat eCos USB testcase// The required information can then be obtained from the previous// line://   T:  Bus=<abc> ... Dev#= <def> ...//// Of course the T: line is going to come first, so it is necessary// to keep track of the current bus and device numbers.//// Note: this code is duplicated in usbchmod.c. Any changes here// should be propagated. For now the routine is too small to warrant// a separate source file.static intusb_scan_devices(int* bus, int* dev){    FILE*       devs_file;    int         current_bus     = -1;    int         current_dev     = -1;    int         ch;    *bus = -1;    *dev = -1;    VERBOSE(1, "Searching " USB_ROOT "devices for the eCos USB test code\n");        devs_file = fopen(USB_ROOT "devices", "r");    if (NULL == devs_file) {        fprintf(stderr, "usbhost: error, unable to access " USB_ROOT "devices\n");        return 0;    }    ch = getc(devs_file);    while (EOF != ch) {        if ('T' == ch) {            if (2 !=fscanf(devs_file, ":  Bus=%d %*[^D\n]Dev#=%d", &current_bus, &current_dev)) {                 current_bus = -1;                current_dev = -1;            }        } else if ('S' == ch) {            int start = 0, end = 0;            if (EOF != fscanf(devs_file, ":  Product=%n" PRODUCT_STRING "%n", &start, &end)) {                if (start < end) {                    *bus = current_bus;                    *dev = current_dev;                    break;                }            }         }        // Move to the end of the current line.        do {            ch = getc(devs_file);        } while ((EOF != ch) && ('\n' != ch));        if (EOF != ch) {            ch = getc(devs_file);        }    }        fclose(devs_file);    if ((-1 != *bus) && (-1 != *dev)) {        VERBOSE(1, "Found eCos USB test code on bus %d, device %d\n", *bus, *dev);        return 1;    }    fprintf(stderr, "usbhost: error, failed to find a USB device \"" PRODUCT_STRING "\"\n");    return 0;}// Actually open the USB device, allowing subsequent ioctl() operations.//// Typically /proc/bus/usb/... will not allow ordinary applications// to perform ioctl()'s. Instead root privileges are required. To work// around this there is a little utility usbchmod, installed suid,// which can be used to get access to the raw device.static intusb_open_device(void){    char devname[_POSIX_PATH_MAX];    static int  bus = -1;    static int  dev = -1;    int         result;        if ((-1 == bus) || (-1 == dev)) {        if (!usb_scan_devices(&bus, &dev)) {            return -1;        }    }        if (_POSIX_PATH_MAX == snprintf(devname, _POSIX_PATH_MAX, USB_ROOT "%03d/%03d", bus, dev)) {        fprintf(stderr, "usbhost: internal error, buffer overflow\n");        exit(EXIT_FAILURE);    }    VERBOSE(1, "Attempting to access USB target via %s\n", devname);        result = open(devname, O_RDWR);    if (-1 == result) {        // Check for access right problems. If so, try to work around them        // by invoking usbchmod. Always look for this in the install tree,        // since it is only that version which is likely to have been        // chown'ed and chmod'ed to be suid root.        if (EACCES == errno) {            char command_name[_POSIX_PATH_MAX];            VERBOSE(1, "Insufficient access to USB target, running usbchmod\n");            if (_POSIX_PATH_MAX == snprintf(command_name, _POSIX_PATH_MAX, "%s/usbchmod %d %d", USBAUXDIR, bus, dev)) {                fprintf(stderr, "usbhost: internal error, buffer overflow\n");                exit(EXIT_FAILURE);            }            (void) system(command_name);            result = open(devname, O_RDWR);        }    }    if (-1 == result) {        fprintf(stderr, "usbhost: error, failed to open \"%s\", errno %d\n", devname, errno);    }    VERBOSE(1, "USB device now accessible via file descriptor %d\n", result);        // Also perform a set-configuration call, to avoid warnings from    // the Linux kernel. Target-side testing is always configuration 1    // because only a single configuration is supported.    (void) ioctl(result, USBDEVFS_SETCONFIGURATION, 1);    return result;}// Exchange a control message with the host. The return value should// be 0, or a small positive number indicating the actual number of// bytes received which may be less than requested.//// There appear to be problems with some hosts, manifesting itself as// an inability to send control messages that involve additional data// from host->target. These problems are not yet well-understood. For// now the workaround is to send multiple packets, each with up to// four bytes encoded in the index and length fields.static intusb_control_message(int fd, int request_type, int request, int value, int index, int length, void* data){    struct usbdevfs_ctrltransfer        transfer;    int         result = 0;    VERBOSE(3, "usb_control_message, request %02x, len %d\n", request, length);        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.requesttype    = USB_TYPE_CLASS | USB_RECIP_DEVICE;            if (this_len > 4) {                this_len = 4;            }

⌨️ 快捷键说明

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