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

📄 usb-linux.c.svn-base

📁 我们自己开发的一个OSEK操作系统!不知道可不可以?
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/* * Linux host USB redirector * * Copyright (c) 2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "qemu-common.h"#include "hw/usb.h"#include "console.h"#if defined(__linux__)#include <dirent.h>#include <sys/ioctl.h>#include <linux/usbdevice_fs.h>#include <linux/version.h>#include <signal.h>/* We redefine it to avoid version problems */struct usb_ctrltransfer {    uint8_t  bRequestType;    uint8_t  bRequest;    uint16_t wValue;    uint16_t wIndex;    uint16_t wLength;    uint32_t timeout;    void *data;};typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,                        int vendor_id, int product_id,                        const char *product_name, int speed);static int usb_host_find_device(int *pbus_num, int *paddr,                                char *product_name, int product_name_size,                                const char *devname);//#define DEBUG//#define DEBUG_ISOCH//#define USE_ASYNCIO#define USBDEVFS_PATH "/proc/bus/usb"#define PRODUCT_NAME_SZ 32#define SIG_ISOCOMPLETE (SIGRTMIN+7)#define MAX_ENDPOINTS 16struct sigaction sigact;/* endpoint association data */struct endp_data {    uint8_t type;};/* FIXME: move USBPacket to PendingURB */typedef struct USBHostDevice {    USBDevice dev;    int fd;    int pipe_fds[2];    USBPacket *packet;    struct endp_data endp_table[MAX_ENDPOINTS];    int configuration;    uint8_t descr[1024];    int descr_len;    int urbs_ready;} USBHostDevice;typedef struct PendingURB {    struct usbdevfs_urb *urb;    int status;    struct PendingURB *next;} PendingURB;static PendingURB *pending_urbs = NULL;static int add_pending_urb(struct usbdevfs_urb *urb){    PendingURB *purb = qemu_mallocz(sizeof(PendingURB));    if (purb) {        purb->urb = urb;        purb->status = 0;        purb->next = pending_urbs;        pending_urbs = purb;        return 1;    }    return 0;}static int del_pending_urb(struct usbdevfs_urb *urb){    PendingURB *purb = pending_urbs;    PendingURB *prev = NULL;    while (purb && purb->urb != urb) {        prev = purb;        purb = purb->next;    }    if (purb && purb->urb == urb) {        if (prev) {            prev->next = purb->next;        } else {            pending_urbs = purb->next;        }        qemu_free(purb);        return 1;    }    return 0;}#ifdef USE_ASYNCIOstatic PendingURB *get_pending_urb(struct usbdevfs_urb *urb){    PendingURB *purb = pending_urbs;    while (purb && purb->urb != urb) {        purb = purb->next;    }    if (purb && purb->urb == urb) {        return purb;    }    return NULL;}#endifstatic int usb_host_update_interfaces(USBHostDevice *dev, int configuration){    int dev_descr_len, config_descr_len;    int interface, nb_interfaces, nb_configurations;    int ret, i;    if (configuration == 0) /* address state - ignore */        return 1;    i = 0;    dev_descr_len = dev->descr[0];    if (dev_descr_len > dev->descr_len)        goto fail;    nb_configurations = dev->descr[17];    i += dev_descr_len;    while (i < dev->descr_len) {#ifdef DEBUG        printf("i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len,               dev->descr[i], dev->descr[i+1]);#endif        if (dev->descr[i+1] != USB_DT_CONFIG) {            i += dev->descr[i];            continue;        }        config_descr_len = dev->descr[i];        if (configuration == dev->descr[i + 5])            break;        i += config_descr_len;    }    if (i >= dev->descr_len) {        printf("usb_host: error - device has no matching configuration\n");        goto fail;    }    nb_interfaces = dev->descr[i + 4];#ifdef USBDEVFS_DISCONNECT    /* earlier Linux 2.4 do not support that */    {        struct usbdevfs_ioctl ctrl;        for (interface = 0; interface < nb_interfaces; interface++) {            ctrl.ioctl_code = USBDEVFS_DISCONNECT;            ctrl.ifno = interface;            ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);            if (ret < 0 && errno != ENODATA) {                perror("USBDEVFS_DISCONNECT");                goto fail;            }        }    }#endif    /* XXX: only grab if all interfaces are free */    for (interface = 0; interface < nb_interfaces; interface++) {        ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);        if (ret < 0) {            if (errno == EBUSY) {                fprintf(stderr,                        "usb_host: warning - device already grabbed\n");            } else {                perror("USBDEVFS_CLAIMINTERFACE");            }        fail:            return 0;        }    }#ifdef DEBUG    printf("usb_host: %d interfaces claimed for configuration %d\n",           nb_interfaces, configuration);#endif    return 1;}static void usb_host_handle_reset(USBDevice *dev){#if 0    USBHostDevice *s = (USBHostDevice *)dev;    /* USBDEVFS_RESET, but not the first time as it has already be       done by the host OS */    ioctl(s->fd, USBDEVFS_RESET);#endif}static void usb_host_handle_destroy(USBDevice *dev){    USBHostDevice *s = (USBHostDevice *)dev;    if (s->fd >= 0)        close(s->fd);    qemu_free(s);}static int usb_linux_update_endp_table(USBHostDevice *s);static int usb_host_handle_control(USBDevice *dev,                                   int request,                                   int value,                                   int index,                                   int length,                                   uint8_t *data){    USBHostDevice *s = (USBHostDevice *)dev;    struct usb_ctrltransfer ct;    struct usbdevfs_setinterface si;    int intf_update_required = 0;    int ret;    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {        /* specific SET_ADDRESS support */        dev->addr = value;        return 0;    } else if (request == ((USB_RECIP_INTERFACE << 8) |                           USB_REQ_SET_INTERFACE)) {        /* set alternate setting for the interface */        si.interface = index;        si.altsetting = value;        ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);        usb_linux_update_endp_table(s);    } else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) {#ifdef DEBUG        printf("usb_host_handle_control: SET_CONFIGURATION request - "               "config %d\n", value & 0xff);#endif        if (s->configuration != (value & 0xff)) {            s->configuration = (value & 0xff);            intf_update_required = 1;        }        goto do_request;    } else {    do_request:        ct.bRequestType = request >> 8;        ct.bRequest = request;        ct.wValue = value;        ct.wIndex = index;        ct.wLength = length;        ct.timeout = 50;        ct.data = data;        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);    }    if (ret < 0) {        switch(errno) {        case ETIMEDOUT:            return USB_RET_NAK;        default:            return USB_RET_STALL;        }    } else {        if (intf_update_required) {#ifdef DEBUG            printf("usb_host_handle_control: updating interfaces\n");#endif            usb_host_update_interfaces(s, value & 0xff);        }        return ret;    }}static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p);static int usb_host_handle_data(USBDevice *dev, USBPacket *p){    USBHostDevice *s = (USBHostDevice *)dev;    struct usbdevfs_bulktransfer bt;    int ret;    uint8_t devep = p->devep;    if (s->endp_table[p->devep - 1].type == USBDEVFS_URB_TYPE_ISO) {        return usb_host_handle_isoch(dev, p);    }    /* XXX: optimize and handle all data types by looking at the       config descriptor */    if (p->pid == USB_TOKEN_IN)        devep |= 0x80;    bt.ep = devep;    bt.len = p->len;    bt.timeout = 50;    bt.data = p->data;    ret = ioctl(s->fd, USBDEVFS_BULK, &bt);    if (ret < 0) {        switch(errno) {        case ETIMEDOUT:            return USB_RET_NAK;        case EPIPE:        default:#ifdef DEBUG            printf("handle_data: errno=%d\n", errno);#endif            return USB_RET_STALL;        }    } else {        return ret;    }}#ifdef USE_ASYNCIOstatic void urb_completion_pipe_read(void *opaque){    USBHostDevice *s = opaque;    USBPacket *p = s->packet;    PendingURB *pending_urb = NULL;    struct usbdevfs_urb *purb = NULL;    int len, ret;    len = read(s->pipe_fds[0], &pending_urb, sizeof(pending_urb));    if (len != sizeof(pending_urb)) {        printf("urb_completion: error reading pending_urb, len=%d\n", len);        return;    }    /* FIXME: handle pending_urb->status */    del_pending_urb(pending_urb->urb);    if (!p) {        s->urbs_ready++;        return;    }    ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb);    if (ret < 0) {        printf("urb_completion: REAPURBNDELAY ioctl=%d errno=%d\n",               ret, errno);        return;    }#ifdef DEBUG_ISOCH    if (purb == pending_urb->urb) {        printf("urb_completion: urb mismatch reaped=%p pending=%p\n",               purb, urb);    }#endif    p->len = purb->actual_length;    usb_packet_complete(p);    qemu_free(purb);    s->packet = NULL;}static void isoch_done(int signum, siginfo_t *info, void *context){    struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr;    USBHostDevice *s = (USBHostDevice *)urb->usercontext;    PendingURB *purb;    if (info->si_code != SI_ASYNCIO ||        info->si_signo != SIG_ISOCOMPLETE) {        return;    }    purb = get_pending_urb(urb);    if (purb) {        purb->status = info->si_errno;        write(s->pipe_fds[1], &purb, sizeof(purb));    }}#endifstatic int usb_host_handle_isoch(USBDevice *dev, USBPacket *p){    USBHostDevice *s = (USBHostDevice *)dev;    struct usbdevfs_urb *urb, *purb = NULL;    int ret;    uint8_t devep = p->devep;    if (p->pid == USB_TOKEN_IN)        devep |= 0x80;    urb = qemu_mallocz(sizeof(struct usbdevfs_urb) +                       sizeof(struct usbdevfs_iso_packet_desc));    if (!urb) {        printf("usb_host_handle_isoch: malloc failed\n");        return 0;    }    urb->type = USBDEVFS_URB_TYPE_ISO;    urb->endpoint = devep;    urb->status = 0;    urb->flags = USBDEVFS_URB_ISO_ASAP;    urb->buffer = p->data;    urb->buffer_length = p->len;    urb->actual_length = 0;    urb->start_frame = 0;    urb->error_count = 0;#ifdef USE_ASYNCIO    urb->signr = SIG_ISOCOMPLETE;#else    urb->signr = 0;#endif    urb->usercontext = s;    urb->number_of_packets = 1;    urb->iso_frame_desc[0].length = p->len;    urb->iso_frame_desc[0].actual_length = 0;    urb->iso_frame_desc[0].status = 0;    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);    if (ret == 0) {        if (!add_pending_urb(urb)) {            printf("usb_host_handle_isoch: add_pending_urb failed %p\n", urb);        }    } else {        printf("usb_host_handle_isoch: SUBMITURB ioctl=%d errno=%d\n",               ret, errno);        qemu_free(urb);        switch(errno) {        case ETIMEDOUT:            return USB_RET_NAK;        case EPIPE:        default:            return USB_RET_STALL;        }    }#ifdef USE_ASYNCIO    /* FIXME: handle urbs_ready together with sync io     * workaround for injecting the signaled urbs into current frame */    if (s->urbs_ready > 0) {        ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb);        if (ret == 0) {            ret = purb->actual_length;            qemu_free(purb);            s->urbs_ready--;        }        return ret;    }    s->packet = p;    return USB_RET_ASYNC;#else    ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb);    if (ret == 0) {        if (del_pending_urb(purb)) {            ret = purb->actual_length;            qemu_free(purb);        } else {            printf("usb_host_handle_isoch: del_pending_urb failed %p\n", purb);        }    } else {#ifdef DEBUG_ISOCH        printf("usb_host_handle_isoch: REAPURBNDELAY ioctl=%d errno=%d\n",               ret, errno);#endif    }    return ret;#endif}

⌨️ 快捷键说明

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