自娱自乐6之Linux gadget驱动5(自编gadget驱动,包涵与之通讯的主机usb驱动,已调试通过)

本文介绍了在Linux环境下,如何调试gadget驱动并实现与主机USB驱动的通信。作者基于zero基础进行修改,包括去掉loop、移除sink读写、添加misc设备通过文件系统读写数据以及删除setup的特殊请求。调试过程中使用了虚拟机作为主机,gadget驱动运行在Linux 3.2.36的板子上,主机端使用的是linux-2.6.18的usb-skeleton驱动。通过双方交互,实现了数据的读写,并观察了拔插USB设备时的行为。
摘要由CSDN通过智能技术生成

这个代码调试,你首先要保证你的udc驱动没用问题,这个有些矛盾,应为我本来要用gadget驱动来调试udc驱动,结果反过来了。

这是在zero基础改的,大概的改动

1. 去掉loop。

2. sink的读写去掉了。

3. 增加了一个misc,通过fs去读写数据。

4. setup的特殊请求去掉了。

之前的文章已经把大部分的东西说完了,所以代码没有太多的注释。请结合之前的文章阅读。

我用了一个完成量,在没有数据时,读可能会死在那。这个可以优化一下,我就不做了。

还有就是主机是虚拟机的usb,linux-2.6.18(无耻的告诉你就是usb-skeleton驱动),gadget是板子的,linux-3.2.36


gadget_transfer.c //linux-3.2.36

/* #define VERBOSE_DEBUG */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/completion.h>
#include <linux/fs.h>

#include <asm/uaccess.h>

#define CONFIG_USB_GADGET_VBUS_DRAW 500

#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"

#define BUFLEN 4096

struct f_sourcesink {
    struct usb_function    function;

    struct usb_ep        *in_ep;
    struct usb_ep        *out_ep;

    struct completion gdt_completion;
    char data[BUFLEN];
    unsigned actual;//数据实际长度
};

static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
{
    return container_of(f, struct f_sourcesink, function);
}

/*-------------------------------------------------------------------------*/
//接口描述符
static struct usb_interface_descriptor source_sink_intf = {
    .bLength =        sizeof source_sink_intf,
    .bDescriptorType =    USB_DT_INTERFACE,

    .bNumEndpoints =    2,
    .bInterfaceClass =    USB_CLASS_VENDOR_SPEC,
    /* .iInterface = DYNAMIC */
};

/* full speed support: */
//全速设备端点描述符
static struct usb_endpoint_descriptor fs_source_desc = {
    .bLength =        USB_DT_ENDPOINT_SIZE,
    .bDescriptorType =    USB_DT_ENDPOINT,

    .bEndpointAddress =    USB_DIR_IN,
    .bmAttributes =        USB_ENDPOINT_XFER_BULK,
};

static struct usb_endpoint_descriptor fs_sink_desc = {
    .bLength =        USB_DT_ENDPOINT_SIZE,
    .bDescriptorType =    USB_DT_ENDPOINT,

    .bEndpointAddress =    USB_DIR_OUT,
    .bmAttributes =        USB_ENDPOINT_XFER_BULK,
};

static struct usb_descriptor_header *fs_source_sink_descs[] = {
    (struct usb_descriptor_header *) &source_sink_intf,
    (struct usb_descriptor_header *) &fs_sink_desc,
    (struct usb_descriptor_header *) &fs_source_desc,
    NULL,
};

/* high speed support: */
//高速设备端点描述符
static struct usb_endpoint_descriptor hs_source_desc = {
    .bLength =        USB_DT_ENDPOINT_SIZE,
    .bDescriptorType =    USB_DT_ENDPOINT,

    .bmAttributes =        USB_ENDPOINT_XFER_BULK,
    .wMaxPacketSize =    cpu_to_le16(512),
};

static struct usb_endpoint_descriptor hs_sink_desc = {
    .bLength =        USB_DT_ENDPOINT_SIZE,
    .bDescriptorType =    USB_DT_ENDPOINT,

    .bmAttributes =        USB_ENDPOINT_XFER_BULK,
    .wMaxPacketSize =    cpu_to_le16(512),
};

static struct usb_descriptor_header *hs_source_sink_descs[] = {
    (struct usb_descriptor_header *) &source_sink_intf,
    (struct usb_descriptor_header *) &hs_source_desc,
    (struct usb_descriptor_header *) &hs_sink_desc,
    NULL,
};


/* function-specific strings: */
static struct usb_string strings_sourcesink[] = {
    [0].s = "source and sink data",
    {  }            /* end of list */
};

static struct usb_gadget_strings stringtab_sourcesink = {
    .language    = 0x0409,    /* en-us */
    .strings    = strings_sourcesink,
};

static struct usb_gadget_strings *sourcesink_strings[] = {
    &stringtab_sourcesink,
    NULL,
};

/*-------------------------------------------------------------------------*/

static const char longname[] = "Gadget gadget_transfer";

#define DRIVER_VENDOR_NUM       0x0ff0          
#define DRIVER_PRODUCT_NUM      0x0ff0          

/*-------------------------------------------------------------------------*/

//usb设备描述符
static struct usb_device_descriptor device_desc = {
    .bLength =        sizeof device_desc,
    .bDescriptorType =    USB_DT_DEVICE,

    .bcdUSB =        cpu_to_le16(0x0200),
    .bDeviceClass =        USB_CLASS_VENDOR_SPEC,

    .idVendor =        cpu_to_le16(DRIVER_VENDOR_NUM),
    .idProduct =        cpu_to_le16(DRIVER_PRODUCT_NUM),
    .bNumConfigurations =    2,
};

/* string IDs are assigned dynamically */

#define STRING_MANUFACTURER_IDX        0
#define STRING_PRODUCT_IDX        1
#define STRING_SERIAL_IDX        2

static char manufacturer[50];

/* default serial number takes at least two packets */
static char serial[] = "0123456789.0123456789.0123456789";

static struct usb_string strings_dev[] = {
    [STRING_MANUFACTURER_IDX].s = manufacturer,
    [STRING_PRODUCT_IDX].s = longname,
    [STRING_SERIAL_IDX].s = serial,
    {  }            /* end of list */
};

static struct usb_gadget_strings stringtab_dev = {
    .language    = 0x0409,    /* en-us */
    .strings    = strings_dev,
};

static struct usb_gadget_strings *dev_strings[] = {
    &stringtab_dev,
    NULL,
};

/*-------------------------------------------------------------------------*/

struct usb_request *alloc_ep_req(struct usb_ep *ep)
{
    struct usb_request    *req;

    //看过之前udc的request,就知道这个就是个kzalloc
    req = usb_ep_alloc_request(ep, GFP_ATOMIC);
    if (req) {
        req->length = BUFLEN;
        req->buf = kmalloc(BUFLEN, GFP_ATOMIC);
        if (!req->buf) {
            usb_ep_free_request(ep, req);
            req = NULL;
        }
    }
    return req;
}

void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
    kfr
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值