linux下如何编写标准USB接口通信程序

                              最近一直在忙研究添加一个标准usb接口的读卡器,经过研究添加成功了,至于什么步骤和原理我就不说了,一切都在代码中,相信对USB有了解肯定能看懂代码,看懂代码那原理流程自然就明白了,呵呵

USB读写实现:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>


#include <sys/ioctl.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <ctype.h>
#include <cutils/log.h>  


#include <linux/usbdevice_fs.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
#include <linux/usb/ch9.h>
#else
#include <linux/usb_ch9.h>
#endif
#include <asm/byteorder.h>


#include <hardware/usb_printer.h>  


#define MAX_RETRIES 5


#define TRACE_USB    1


#ifdef TRACE_USB
#define DBG1(x...) LOGI(stderr, x)
#define DBG(x...)  LOGI(stderr, x)
#else
#define DBG(x...)
#define DBG1(x...)
#endif






#define XDEBUG(X...) do { \
      LOGI("\nTRACE--[File: %s]--[Line: %d]--[Function: %s]--INFO:", \
      __FILE__, __LINE__,__FUNCTION__); LOGI(X);\
   }while(0) 


#define XDEERR(X...) do { \
      LOGE("\nTRACE--[File: %s]--[Line: %d]--[Function: %s]--INFO:", \
      __FILE__, __LINE__,__FUNCTION__); LOGE(X);\
   }while(0) 






static int match_null(usb_ifc_info *info)
{
 XDEBUG("match_nul lnto i\n");
    if(!info)
    {
        XDEERR("match_null fail\n");
        return -1;
    }
    if(info->dev_vendor != 0x154f) return -1; 
    //if(info->dev_product != 0x154f) return -1;
    XDEBUG("match_null sucess\n");
  
    return 0;
}


static inline int badname(const char *name)
{
    while(*name) {
        if(!isdigit(*name++)) return 1;
    }
    return 0;
}


static int check(void *_desc, int len, unsigned type, int size)
{
    unsigned char *desc = _desc;
    
    if(len < size) return -1;
    if(desc[0] < size) return -1;
    if(desc[0] > len) return -1;
    if(desc[1] != type) return -1;
    
    return 0;
}


static int filter_usb_device(int fd, char *ptr, int len, int writable,
                             int *ept_in_id, int *ept_out_id, int *ifc_id)
{
    struct usb_device_descriptor *dev;
    struct usb_config_descriptor *cfg;
    struct usb_interface_descriptor *ifc;
    struct usb_endpoint_descriptor *ept;
    struct usb_ifc_info info;
    
    int in, out;
    unsigned i;
    unsigned e;
    
    if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
        return -1;
    dev = (void*) ptr;
    len -= dev->bLength;
    ptr += dev->bLength;
    
    if(check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
        return -1;
    cfg = (void*) ptr;
    len -= cfg->bLength;
    ptr += cfg->bLength;
    
    info.dev_vendor = dev->idVendor;
    info.dev_product = dev->idProduct;
    info.dev_class = dev->bDeviceClass;
    info.dev_subclass = dev->bDeviceSubClass;
    info.dev_protocol = dev->bDeviceProtocol;
    info.writable = writable;
    
    // read device serial number (if there is one)
    info.serial_number[0] = 0;
    if (dev->iSerialNumber) {
        struct usbdevfs_ctrltransfer  ctrl;
        __u16 buffer[128];
        int result;


        memset(buffer, 0, sizeof(buffer));


        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
        ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
        ctrl.wIndex = 0;
        ctrl.wLength = sizeof(buffer);
        ctrl.data = buffer;
   ctrl.timeout = 50;


        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
        if (result > 0) {
            int i;
            // skip first word, and copy the rest to the serial string, changing shorts to bytes.
            result /= 2;
            for (i = 1; i < result; i++)
                info.serial_number[i - 1] = buffer[i];
            info.serial_number[i - 1] = 0;
        }
    }
    for(i = 0; i < cfg->bNumInterfaces; i++) {
        if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
        {
             return -1;
          }
        ifc = (void*) ptr;
        len -= ifc->bLength;
        ptr += ifc->bLength;
        
        in = -1;
        out = -1;
        info.ifc_class = ifc->bInterfaceClass;
        info.ifc_subclass = ifc->bInterfaceSubClass;
        info.ifc_protocol = ifc->bInterfaceProtocol;
        
        for(e = 0; e < ifc->bNumEndpoints; e++) {
            if(check(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
            {
             XDEBUG("fail check f\n");
                return -1;
             }
            ept = (void*) ptr;
            len -= ept->bLength;
            ptr += ept->bLength;
    
            if((ept->bmAttributes & 0x03) != 0x02)
                continue;
            
            if(ept->bEndpointAddress & 0x80) {
                in = ept->bEndpointAddress;
            } else {
                out = ept->bEndpointAddress;
            }
        }


        info.has_bulk_in = (in != -1);
        info.has_bulk_out = (out != -1);
        XDEBUG("info.dev_vendor[0x%x]\n",info.dev_vendor);
        if(match_null(&info) == 0) {
            *ept_in_id = in;
            *ept_out_id = out;
            *ifc_id = ifc->bInterfaceNumber;
            return 0;
        }
    }


    return -1;
}




static int usb_write(usb_handle *h, const void *_data, int len)
{
    unsigned char *data = (unsigned char*) _data;
    unsigned count = 0;
    struct usbdevfs_bulktransfer bulk;
    int n;


    if(h->ep_out == 0) {
        return -1;
    }
    if(len == 0) {
        bulk.ep = h->ep_out;
        bulk.len = 0;
        bulk.data = data;
        bulk.timeout = 0;
        n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
        if(n != 0) {
       
           XDEBUG("usb_write ERROR\n");
            fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
                    n, errno, strerror(errno));
            return -1;
        }
        return 0;
    }
    
    while(len > 0) {
        int xfer;
        xfer = (len > 4096) ? 4096 : len;
        
        bulk.ep = h->ep_out;
        bulk.len = xfer;
        bulk.data = data;
        bulk.timeout = 0;
        n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
        if(n != xfer) {
       
            DBG("ERROR: n = %d, errno = %d (%s)\n",
                n, errno, strerror(errno));
            return -1;
        }


        count += xfer;
        len -= xfer;
        data += xfer;
    }


    return count;
}




static usb_handle *usb_open(const char *base)
{
    usb_handle *usb = 0;
    char busname[64], devname[64];
    char desc[1024];
    int n, in, out, ifc;
    
    DIR *busdir, *devdir;
    struct dirent *de;
    int fd;
    int writable;
    
    busdir = opendir(base);
    if(busdir == 0) return 0;
    while((de = readdir(busdir)) && (usb == 0)) {
        if(badname(de->d_name)) continue;
        
        sprintf(busname, "%s/%s", base, de->d_name);
        devdir = opendir(busname);
        if(devdir == 0) continue;
        
        DBG("[ scanning %s ]\n", busname);
        while((de = readdir(devdir)) && (usb == 0)) {
            XDEBUG("readdir\n");
            if(badname(de->d_name)) continue;
            sprintf(devname, "%s/%s", busname, de->d_name);


            DBG("[ scanning %s ]\n", devname);
            writable = 1;
            if((fd = open(devname, O_RDWR)) < 0) {
                // Check if we have read-only access, so we can give a helpful
                // diagnostic like "adb devices" does.
                writable = 0;
                if((fd = open(devname, O_RDONLY)) < 0) {
                    continue;
                }
            }
            n = read(fd, desc, sizeof(desc));
            
            if(filter_usb_device(fd, desc, n, writable, 
                                 &in, &out, &ifc) == 0) 
            {
                usb = calloc(1, sizeof(usb_handle));
                strcpy(usb->fname, devname);
                usb->ep_in = in;
                usb->ep_out = out;
                usb->desc = fd;
                n = ioctl(fd, USBDEVFS_CLAIMINTERFA, &ifc);
                if(n != 0) {
                    close(fd);
                    free(usb);
                    usb = 0;
                    continue;
                }
            } else {
                close(fd);
            }
        }
        closedir(devdir);
    }
    closedir(busdir);


    return usb;
}


static int usb_close(usb_handle *h)
{
    int fd;
    if(h)
    {
       fd = h->desc;
       h->desc = -1;
       if(fd >= 0) 
       {
           close(fd);
           DBG("[ usb closed %d ]\n", fd);
       }
    free(h);
//     h=0;
    return 0;
}
    return -1;
}


测试代码,具体要查看你的设备VPID资料和端点来修改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "usb.h"


static unsigned arg_size = 4096;
static unsigned arg_count = 4096;


long long NOW(void) 
{
    struct timeval tv;
    gettimeofday(&tv, 0);
    
    return (((long long) tv.tv_sec) * ((long long) 1000000)) +
        (((long long) tv.tv_usec));
}


int printifc(usb_ifc_info *info)
{
    printf("dev: csp=%02x/%02x/%02x v=%04x p=%04x  ",
           info->dev_class, info->dev_subclass, info->dev_protocol,
           info->dev_vendor, info->dev_product);
    printf("ifc: csp=%02x/%02x/%02x%s%s\n",
           info->ifc_class, info->ifc_subclass, info->ifc_protocol,
           info->has_bulk_in ? " in" : "",
           info->has_bulk_out ? " out" : "");
    return -1;
}


int match_null(usb_ifc_info *info)
{
    if(!info)
    {
        printf("match_null\n");
        return -1;
    }
    //if(info->dev_vendor != 0x0400) return -1; 
    if(info->dev_vendor != 0x154f) return -1; 
    if(info->dev_vendor != 0x18d1) return -1;
    if(info->ifc_class != 0xff) return -1;
    if(info->ifc_subclass != 0xfe) return -1;
    if(info->ifc_protocol != 0x01) return -1;
    return 0;
}


int match_zero(usb_ifc_info *info)
{


    if(!info)
    {
        printf("match_zero\n");
        return -1;
    }
    //if(info->dev_vendor != 0x0400) return -1;
    if(info->dev_vendor != 0x154f) return -1; 
    if(info->dev_vendor != 0x18d1) return -1;
    if(info->ifc_class != 0xff) return -1;
    if(info->ifc_subclass != 0xfe) return -1;
    if(info->ifc_protocol != 0x02) return -1;
    return 0;
}


int match_loop(usb_ifc_info *info)
{
    if(!info)
    {
        printf("match_loop\n");
        return -1;
    }
    //if(info->dev_vendor != 0x0400) return -1;
    if(info->dev_vendor != 0x154f) return -1; 
    if(info->dev_vendor != 0x18d1) return -1;
    if(info->ifc_class != 0xff) return -1;
    if(info->ifc_subclass != 0xfe) return -1;
    if(info->ifc_protocol != 0x03) return -1;
    return 0;
}


int test_null(usb_handle *usb)
{
    int i;
    char buf[]="1234567890";
    int datalen = sizeof(buf);
    //memset(buf, 0xee, 4096);
    long long t0, t1;


    t0 = NOW();
    printf("test_null\n");
    if(usb_write(usb, buf, sizeof(buf)) != datalen)
    {
        fprintf(stderr,"write failed (%s)\n", strerror(errno));
        return -1;
    }
    t1 = NOW();
    fprintf(stderr,"%d bytes in %lld uS\n", datalen, (t1 - t0));
    return 0;


    #if 0
    t0 = NOW();
    for(i = 0; i < arg_count; i++) {
        if(usb_write(usb, buf, arg_size) != arg_size) {
            fprintf(stderr,"write failed (%s)\n", strerror(errno));
            return -1;
        }
    }
    t1 = NOW();
    fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
    return 0;
    #endif
    
}




int test_err_data(usb_handle *usb)
{
    int i;
    unsigned char buf[100];
    int datalen = 100;
    memset(buf, 0xee, datalen);
    long long t0, t1;


    t0 = NOW();
    printf("test_err_data\n");
    if(usb_write(usb, buf, 100) != datalen)
    {
        fprintf(stderr,"write failed (%s)\n", strerror(errno));
        return -1;
    }
    t1 = NOW();
    fprintf(stderr,"%d bytes in %lld uS\n", datalen, (t1 - t0));
    return 0;   
}


int test_read(usb_handle *usb)
{
    int i,len;
    unsigned char buf[4096];
    long long t0, t1;
    
    t0 = NOW();
    len = 0;
    
    len = usb_read(usb, buf, 100);
    if(!len)
    {
        fprintf(stderr,"read failed (%s)\n", strerror(errno));
        return -1;
    }


    t1 = NOW();
    fprintf(stderr,"%d bytes in %lld uS\n", len, (t1 - t0));
    int j;
    for( j =0;j<len;j++)
    {
         printf("buf[%d]",buf[j]);
    }
    printf("\n");
    return 0;
}








int test_zero(usb_handle *usb)
{
    int i;
    unsigned char buf[4096];
    long long t0, t1;
    
    t0 = NOW();
    for(i = 0; i < arg_count; i++) {
        if(usb_read(usb, buf, arg_size) != arg_size) {
            fprintf(stderr,"read failed (%s)\n", strerror(errno));
            return -1;
        }
    }
    t1 = NOW();
    fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
    return 0;
}


struct 
{
    const char *cmd;
    ifc_match_func match;
    int (*test)(usb_handle *usb);
    const char *help;
} tests[] = {
    { "list", printifc,   0,         "list interfaces" },
    { "send", match_null, test_null, "send to null interface" },
    { "senderr", match_null, test_err_data, "send err to null interface" }, 
    { "read", match_zero, test_read, "recv from zero interface" },    
    { "recv", match_zero, test_zero, "recv from zero interface" },
    { "loop", match_loop, 0,         "exercise loopback interface" },
    {},
};


int usage(void)
{
    int i;


    fprintf(stderr,"usage: usbtest <testname>\n\navailable tests:\n");
    for(i = 0; tests[i].cmd; i++) {
        fprintf(stderr," %-8s %s\n", tests[i].cmd, tests[i].help);
    }
    return -1;
}


int process_args(int argc, char **argv)
{
    while(argc-- > 0) {
        char *arg = *argv++;
        if(!strncmp(arg,"count=",6)) {
            arg_count = atoi(arg + 6);
        } else if(!strncmp(arg,"size=",5)) {
            arg_size = atoi(arg + 5);
        } else {
            fprintf(stderr,"unknown argument: %s\n", arg);
            return -1;
        }
    }


    if(arg_count == 0) {
        fprintf(stderr,"count may not be zero\n");
        return -1;
    }


    if(arg_size > 4096) {
        fprintf(stderr,"size may not be greater than 4096\n");
        return -1;
    }


    return 0;
}


int main(int argc, char **argv)
{
    usb_handle *usb;
    int i;


    printf("test  print\n");
    if(argc < 2)
        return usage();


    if(argc > 2) {
        if(process_args(argc - 2, argv + 2)) 
            return -1;
    }
    printf("test  hehe\n");
    for(i = 0; tests[i].cmd; i++) {
        if(!strcmp(argv[1], tests[i].cmd)) {
            usb = usb_open(tests[i].match);
            if(tests[i].test) {
                if(usb == 0) {
                    fprintf(stderr,"usbtest: %s: could not find interface\n",
                            tests[i].cmd);
                    return -1;
                }
                if(tests[i].test(usb)) {
                    fprintf(stderr,"usbtest: %s: FAIL\n", tests[i].cmd);
                    return -1;
                } else {
                    fprintf(stderr,"usbtest: %s: OKAY\n", tests[i].cmd);
                }
            }
            return 0;
        }
        else if(!strcmp(argv[1], "q"))
        {
           return 0;
        }
    }
cleanup:
    sleep(1);
    return usage();
     exit(1);
}






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Linux下,编写USB设备驱动程序的过程可以分为以下几个步骤: 1. 确定驱动程序的框架:一般情况下,驱动程序需要使用Linux内核提供的USB子系统进行通信。可以选择使用USB核心驱动框架,如usbcore或者usbfs,这取决于驱动程序的需求和功能。 2. 编写设备识别和初始化函数:USB设备在Linux系统中由Vendor ID(厂商ID)和Product ID(产品ID)唯一标识。在驱动程序中,需要编写设备识别函数,通过与系统中的已知设备进行匹配,确定设备的类型和特性。然后,初始化设备的状态和资源。 3. 实现设备的控制和数据传输:USB设备通常具有多个接口和端点,每个端点的功能和方向都不同。驱动程序需要实现设备的控制和数据传输功能,包括读取设备的描述符、配置设备、发送和接收数据等。 4. 处理中断和事件:某些USB设备可能会产生中断或者其他事件,这需要驱动程序对这些事件进行处理。可以注册中断处理程序或事件处理程序,并根据设备的需求进行响应。 5. 编写设备文件操作函数:Linux系统将USB设备作为设备文件进行管理。驱动程序需要编写打开、关闭、读取、写入等操作函数,将应用程序的请求传递给对应的设备。 6. 编译和加载驱动程序:完成驱动程序编写后,需要将其编译成模块或者内核。通过insmod命令将驱动程序模块加载到内核中,然后可以通过udev等工具进行设备的管理和配置。 编写USB设备驱动程序需要对Linux内核有一定的了解,了解USB协议和接口规范,掌握Linux内核编程的基本知识。同时,还需要通过查阅文档和示例代码来学习和理解USB设备驱动程序编写方法和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值