继续写usb gadget驱动(还是遇到坑了...传输不通...)

哎, 还是遇到坑了...传输不通...

直接贴代码记录下吧, 后面继续调...

#include <linux/module.h>
#include <linux/kernel.h>  /* min() */
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/usb/gadget.h>
#include <linux/stacktrace.h>
#include <linux/string.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("River");

#define USB_BUFSIZE 256

struct g_loop_dev {
    struct usb_gadget *gadget;      // gadget device
    struct usb_request *req;       // for ep0 request
    struct usb_ep *out_ep;          // TBD: for ep out transfer
    // struct cdev cdev;               // TBD: char dev
};

#define STR_ID_MANUFACTURER 25
#define STR_ID_PRODUCT 42
#define STR_ID_SERIAL 101
#define STR_ID_LOOPBACK 251

/* my specific vid&pid */
#define DRIVER_VENDOR_NUM 0x1234
#define DRIVER_PRODUCT_NUM 0x5678

// #define DRIVER_VENDOR_NUM	0x0525		/* NetChip */
// #define DRIVER_PRODUCT_NUM	0xa4a0		/* Linux-USB "Gadget Zero" */

static struct usb_device_descriptor device_desc = {
    .bLength = sizeof (device_desc),
    .bDescriptorType = USB_DT_DEVICE,

    .bcdUSB = __constant_cpu_to_le16(0x0320),
    // .bcdUSB = __constant_cpu_to_le16(0x0201),
    .bDeviceClass = USB_CLASS_VENDOR_SPEC,
    .bMaxPacketSize0 = 9,
    .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
    .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
    .iManufacturer = STR_ID_MANUFACTURER,
    .iProduct = STR_ID_PRODUCT,
    .iSerialNumber = STR_ID_SERIAL,
    .bNumConfigurations = 1,
};

static struct usb_config_descriptor g_loop_config = {
    .bLength = sizeof g_loop_config,
    .bDescriptorType = USB_DT_CONFIG,

    .bNumInterfaces = 1,
    .bConfigurationValue = 1,
    .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
    .bMaxPower = 1, /* self-powered */
};

/* interface descriptor */
static struct usb_interface_descriptor g_loop_interface = {
    .bLength = sizeof(g_loop_interface),
    .bDescriptorType = USB_DT_INTERFACE,

    .bNumEndpoints = 1,
    .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
    .iInterface = STR_ID_LOOPBACK,
};

/* endpoint descriptor */
static struct usb_endpoint_descriptor fs_sink_desc = {
    .bLength = USB_DT_ENDPOINT_SIZE,
    .bDescriptorType= USB_DT_ENDPOINT,

    .bEndpointAddress = USB_DIR_OUT,    // for pc host, it is out ep.
    .bmAttributes = USB_ENDPOINT_XFER_BULK,
    .wMaxPacketSize = __constant_cpu_to_le16(1024),
};

static struct usb_ss_ep_comp_descriptor ss_fs_sink_comp_desc = {
    .bLength = sizeof(ss_fs_sink_comp_desc),
    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
	.bMaxBurst = 0,
	.bmAttributes = 0,
	.wBytesPerInterval = 0,
};

/* function/interface description... */
static const struct usb_descriptor_header *fs_g_loop_function[] = {
    (struct usb_descriptor_header *) &g_loop_interface,
    (struct usb_descriptor_header *) &fs_sink_desc,
    (struct usb_descriptor_header *) &ss_fs_sink_comp_desc,
    NULL,
};

static struct usb_string strings[] = {
    {STR_ID_MANUFACTURER, "river run", },
    {STR_ID_PRODUCT,      "river loop", },
    {STR_ID_SERIAL,       "1234567890", },
    {STR_ID_LOOPBACK,       "loop in to out", },
    {  },
};

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

static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
	kfree(req->buf);
	usb_ep_free_request(ep, req);
}

static void g_loop_setup_complete(struct usb_ep *ep,
        struct usb_request *req) {

    printk(KERN_INFO "g_loop_setup complete --> %d, %d, %d\n",
                    req->status, req->actual, req->length);

    return;
}


static void sourcesink_complete(struct usb_ep *ep,
        struct usb_request *req) {
    int status = 0;

    printk(KERN_INFO "sourcesink complete --> %d, %d, %d\n",
                    req->status, req->actual, req->length);

    if (req->status) {
        printk(KERN_ERR "some error happen...\n");
        return;
    }

    printk(KERN_INFO "usb received: %s\n", (char *)req->buf);

    status = usb_ep_queue(ep, req, GFP_ATOMIC);
    if (status) {
        printk(KERN_ERR "usb_ep_queue resubmit failed...\n");
    }

    return;
}

static int sourcesink_start_ep(struct usb_ep *ep)
{
    int ret = 0;
    struct usb_request *req;

    req = usb_ep_alloc_request(ep, GFP_KERNEL);
    if (!req) {
        ret = -ENOMEM;
        goto request_fail;
    }

    req->buf = kzalloc(USB_BUFSIZE, GFP_KERNEL);
    if (!req->buf) {
        ret = -ENOMEM;
        goto malloc_fail;
    }

    req->complete = sourcesink_complete;

    ret = usb_ep_queue(ep, req, GFP_ATOMIC);
    if (ret < 0) {
        printk(KERN_ERR "usb_ep_queue failed...\n");
        goto epqueue_failed;
    }

    printk(KERN_INFO "sourcesink start ep succeed\n");

    return 0;

epqueue_failed:
    kfree(req->buf);

malloc_fail:
	usb_ep_free_request(ep, req);

request_fail:
    return ret;
}

static void sourcesink_reset_config(struct g_loop_dev *dev) // reset config
{
    usb_ep_disable(dev->out_ep);
    // dev->out_ep = NULL;
}

static int set_sourcesink_config(struct g_loop_dev *dev)
{
    int result = 0;
    struct usb_ep *ep;

    printk(KERN_INFO "set_sourcesink_config\n");

    ep=dev->out_ep;
    ep->maxpacket = usb_endpoint_maxp(&fs_sink_desc);
    ep->desc = &fs_sink_desc;
    ep->comp_desc = NULL;

    printk(KERN_INFO "try usb_ep_enable\n");
    result = usb_ep_enable(ep); // active ep (bulk out)

    if (result == 0) {
        printk("connected\n");
        sourcesink_start_ep(ep);
    } else {
        printk("can't enable %s, result %d\n", ep->name, result);
    }

    return result;
}

static int g_loop_dev_prepare(struct g_loop_dev *dev) {
	struct usb_gadget *gadget = dev->gadget;
	int ret;

    /* reset ep autoconfig state */
	usb_ep_autoconfig_reset(gadget);

    /* config & prepare an endpoint */
    dev->out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc);

    if (!dev->out_ep) {
        printk(KERN_ERR "usb_ep_autoconfig failed\n");
        ret = - ENOMEM;
        goto config_fail;
    }

    printk(KERN_INFO "ep_desc = %p\n", dev->out_ep->desc);
    printk(KERN_INFO "fs_sink_desc = %p\n", &fs_sink_desc);
    printk(KERN_INFO "ep->addr = %d\n", dev->out_ep->address);
    printk(KERN_INFO "ep->claimed = %d\n", dev->out_ep->claimed);
    printk(KERN_INFO "ep->enabled = %d\n", dev->out_ep->enabled);

    printk(KERN_INFO "usb_ep_autoconfig succeed\n");

	/* preallocate control response and buffer */
	dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
	if (!dev->req) {
		ret = -ENOMEM;
        goto ep_fail;
    }

	dev->req->buf = kzalloc(USB_BUFSIZE, GFP_KERNEL);
	if (!dev->req->buf)
		goto malloc_fail;

	dev->req->complete = g_loop_setup_complete;
	dev->req->context = dev;
	gadget->ep0->driver_data = dev;

	usb_gadget_set_selfpowered(gadget);

	return 0;

malloc_fail:
	usb_ep_free_request(gadget->ep0, dev->req);
	dev->req = NULL;

ep_fail:

config_fail:


    return ret;
}

static int g_loop_bind(struct usb_gadget *gadget,
        struct usb_gadget_driver *driver) {
    int ret = 0;
    struct g_loop_dev *dev;

    if (!gadget ||!driver) {
        ret = -EINVAL;
        goto invalid_param;
    }

    printk(KERN_INFO "gadget info: speed(%d), max_speed(%d)",
                gadget->speed, gadget->max_speed);

    printk(KERN_INFO "gadget info: maxpacket(%d), claimed(%d), enabled(%d)",
                gadget->ep0->maxpacket, gadget->ep0->claimed?1:0,
                gadget->ep0->enabled?1:0);


    dev = kzalloc(sizeof(struct g_loop_dev), GFP_KERNEL);
    if (!dev) {
        printk(KERN_ERR "malloc failed for g_loop_dev\n");
        ret = -ENOMEM;
        goto malloc_fail;
    }

	dev->gadget = gadget;
	set_gadget_data(gadget, dev);

    /* bMaxPacketSize format is 2^bMaxPacketSize0, eg, 2^9 = 512 */
    // device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;

    ret = g_loop_dev_prepare(dev);
    if (ret < 0) {
        printk(KERN_ERR "g_loop_dev_prepare failed...\n");
        goto prepare_fail;
    }

    printk(KERN_INFO "simple composite ready...\n");

    return ret;

prepare_fail:
    if (dev) {
        kfree(dev);
        dev = NULL;
    }

malloc_fail:
invalid_param:

    return ret;
}

static void g_loop_unbind(struct usb_gadget *gadget) {
    struct g_loop_dev *dev = get_gadget_data(gadget);

    if (dev->req) {
        dev->req->length= USB_BUFSIZE;
        free_ep_req(gadget->ep0, dev->req);
    }

    kfree(dev);

    set_gadget_data(gadget, NULL);

    printk(KERN_INFO "g_loop_unbind callback complete\n");

    return;
}

static int config_buf(struct usb_gadget *gadget,
                      u8 *buf, u8 type, unsigned index)
{
    //int is_source_sink;
    int len;
    const struct usb_descriptor_header **function;

    printk(KERN_INFO "config_buf, type = %d, index = %d\n",
                type, index);

    function = fs_g_loop_function;

    len = usb_gadget_config_buf(&g_loop_config,
                      buf, USB_BUFSIZE, function);
    if (len < 0)
        return len;

    ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
    return len;
}

/**
 * bos_desc() - prepares the BOS descriptor.
 * @cdev: pointer to usb_composite device to generate the bos
 *	descriptor for
 *
 * This function generates the BOS (Binary Device Object)
 * descriptor and its device capabilities descriptors. The BOS
 * descriptor should be supported by a SuperSpeed device.
 */
static int bos_desc(struct usb_gadget *gadget,
                    const struct usb_request *req) {
	struct usb_ext_cap_descriptor	*usb_ext;
	struct usb_dcd_config_params	dcd_config_params;
	struct usb_bos_descriptor	*bos = req->buf;

	bos->bLength = USB_DT_BOS_SIZE;
	bos->bDescriptorType = USB_DT_BOS;

	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
	bos->bNumDeviceCaps = 0;

	/*
	 * A SuperSpeed device shall include the USB2.0 extension descriptor
	 * and shall support LPM when operating in USB2.0 HS mode.
	 */
	usb_ext = req->buf + le16_to_cpu(bos->wTotalLength);
	bos->bNumDeviceCaps++;
	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);

	/*
	 * The Superspeed USB Capability descriptor shall be implemented by all
	 * SuperSpeed devices.
	 */
	if (gadget_is_superspeed(gadget)) {
		struct usb_ss_cap_descriptor *ss_cap;

		ss_cap = req->buf + le16_to_cpu(bos->wTotalLength);
		bos->bNumDeviceCaps++;
		le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
		ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
		ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
		ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
		ss_cap->bmAttributes = 0; /* LTM is not supported yet */
		ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
						      USB_FULL_SPEED_OPERATION |
						      USB_HIGH_SPEED_OPERATION |
						      USB_5GBPS_OPERATION);
		ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;

		/* Get Controller configuration */
		if (gadget->ops->get_config_params) {
			gadget->ops->get_config_params(
				&dcd_config_params);
		} else {
			dcd_config_params.bU1devExitLat =
				USB_DEFAULT_U1_DEV_EXIT_LAT;
			dcd_config_params.bU2DevExitLat =
				cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
		}
		ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
		ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
	}

	return le16_to_cpu(bos->wTotalLength);
}

static int g_loop_set_config(struct g_loop_dev *dev, unsigned number)
{
    int result = 0;
    // struct usb_gadget *gadget = dev->gadget;

    printk(KERN_INFO "set config, number = %d\n", number);

    result = set_sourcesink_config(dev); // active device
    if (result < 0) {
        printk(KERN_ERR "set loopback config failed\n");
        sourcesink_reset_config(dev); // reset device
        return result;
    }

    printk(KERN_ERR "set loopback config succeed\n");

    return result;
}

/*
 * ep0 setup callback, we need to tell what kind of
 * device we are...
 * according to ch9, we need to response to get_descriptor
 * control command...
 */
static int g_loop_setup(struct usb_gadget *gadget,
                    const struct usb_ctrlrequest *ctl_req) {
    struct g_loop_dev *loop_dev = get_gadget_data(gadget);
    struct usb_request *req = NULL;
    int value = 0;
    // u16 w_index = le16_to_cpu(ctl_req->wIndex);
    u16 w_value = le16_to_cpu(ctl_req->wValue);
    u16 w_length = le16_to_cpu(ctl_req->wLength);
    int ret = 0;
    int i = 0;
    unsigned char *buf;

    printk(KERN_INFO "g_loop_setup callback\n");

    if (!loop_dev) {
        ret = -EFAULT;
        goto unknown;
    }

    req = loop_dev->req;
    buf = req->buf;

    // dump_stack();

    printk(KERN_INFO "setup request: %d, desc_type: 0x%x, "
            "w_lenght:%d\n",
            ctl_req->bRequest, w_value>>8, w_length);

    switch (ctl_req->bRequest) {

    /* handle some standard request... */
    case USB_REQ_GET_DESCRIPTOR: {
        if (ctl_req->bRequestType != USB_DIR_IN ) {
            printk(KERN_ERR "error request type(0x%x)\n",
                    ctl_req->bRequestType);
            ret = -EFAULT;
            goto unknown;
        }

        /* high byte means descriptor type,
         * descriptor index in low byte...
         */
        switch (w_value>>8) {

        case USB_DT_DEVICE:
            printk(KERN_INFO "get desc for USB_DT_DEVICE\n");
            value = min(w_length, (u16) sizeof device_desc);
            memcpy(req->buf, &device_desc,
                    value);

            break;
        case USB_DT_CONFIG:
            printk(KERN_INFO "get desc for USB_DT_CONFIG\n");
            /* use some help function fill config descriptor... */
            value = config_buf(gadget, req->buf,
                        w_value >> 8,
                        w_value & 0xff);
            if (value >= 0)
                value = min(w_length, (u16) value);

            break;
        case USB_DT_STRING:
            printk(KERN_INFO "get desc for USB_DT_STRING\n");
            value = usb_gadget_get_string(&string_table, w_value&0xff,
                                    req->buf);
            if (value >= 0)
                value = min(w_length, (u16) value);
            break;

        case USB_DT_OTG:
            printk(KERN_INFO "get desc for USB_DT_OTG, TBD...\n");
            break;

        case USB_DT_BOS:
            printk(KERN_INFO "get desc for USB_DT_BOS\n");
			if (gadget_is_superspeed(gadget)) {
				value = bos_desc(gadget, req);
				value = min(w_length, (u16) value);
			}
			break;

        default:
            printk(KERN_INFO "descriptor type: %d, do nothing\n",
                    w_value>>8);
            break;
        }
    }

    break;

    case USB_REQ_SET_DESCRIPTOR:
        printk(KERN_INFO "set descriptor request, do nothing...\n");
        break;

    case USB_REQ_GET_CONFIGURATION:
        printk(KERN_INFO "get configuration request, do nothing...\n");
        break;

    case USB_REQ_SET_CONFIGURATION:
        printk(KERN_INFO "set configuration request\n");

        if (ctl_req->bRequestType != 0) {
            ret = -EFAULT;
            goto unknown;
        }

		/* resets interface configuration, forgets about
		 * previous transaction state (queued bufs, etc)
		 * and re-inits endpoint state (toggle etc)
		 * no response queued, just zero status == success.
		 * if we had more than one interface we couldn't
		 * use this "reset the config" shortcut.
		 */

		// g_loop_set_config(loop_dev, w_value, GFP_ATOMIC);
		g_loop_set_config(loop_dev, w_value);
		value = 0;

        break;

    case USB_REQ_GET_INTERFACE:
        printk(KERN_INFO "get interfafe request, do nothing...\n");
        break;

    case USB_REQ_SET_INTERFACE:
        printk(KERN_INFO "set interfafe request, do nothing...\n");
        break;

    default:
        printk(KERN_INFO "bRequestType - %d, no handler...\n",
                    ctl_req->bRequestType);
        break;
    }

    if (value <= 0) {
        printk(KERN_ERR "no data needs to be sent\n");
        ret = -EFAULT;
        goto do_nothing;
    }

    printk(KERN_INFO "buf:\n");
    for (i=0; i<value; i++) {
        printk(KERN_CONT "0x%x ", buf[i]);
        if ((i+1)%9 == 0) {
            printk(KERN_CONT "\n");
        }
    }
    printk(KERN_CONT "\n");

    req->length = value;
    req->zero = value < w_length;
    printk(KERN_INFO "value: %d, w_length: %d\n",
            value, w_length);
    printk(KERN_INFO "req->zero: %d\n", req->zero);

    ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
    if (ret < 0) {
        printk(KERN_ERR "usb_ep_queue failed, ret(%d)\n", ret);
        req->status = 0;
        g_loop_setup_complete(gadget->ep0, req);
    }

    return ret;

do_nothing:
unknown:
    return ret;
}

static void g_loop_reset(struct usb_gadget *gadget) {
    printk(KERN_INFO "g_loop_reset callback\n");

    usb_ep_autoconfig_reset(gadget);

    return;
}

static void g_loop_disconnect(struct usb_gadget *gadget) {
    printk(KERN_INFO "g_loop_disconnect callback\n");

    return;
}

static struct usb_gadget_driver g_loop_driver = {
    .function = "gadget_g_loop",
    .max_speed = USB_SPEED_SUPER,
    // .max_speed = USB_SPEED_HIGH,
    .bind = g_loop_bind,
    .unbind = g_loop_unbind,
    .setup = g_loop_setup,
    .reset = g_loop_reset,
    .disconnect = g_loop_disconnect,
};

static int __init g_loop_init(void) {
    int ret = 0;

    printk(KERN_INFO "g_loop_init in\n");

    ret = usb_gadget_probe_driver(&g_loop_driver);

    if (ret < 0) {
        printk(KERN_ERR "usb gaget driver register failed, "
                "ret(%d)\n", ret);
        goto probe_failed;
    }

    printk(KERN_INFO "g_loop_init succeed\n");

    return 0;

probe_failed:

    return ret;
}

static void __exit g_loop_exit(void) {
    printk(KERN_INFO "g_loop_exit in\n");

    usb_gadget_unregister_driver(&g_loop_driver);

    printk(KERN_INFO "g_loop_exit succeed\n");

    return;
}

module_init(g_loop_init);
module_exit(g_loop_exit);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值