这个代码调试,你首先要保证你的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)
{
kfree(req->buf);
usb_ep_free_request(ep, req);
} static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
{
int value; if (ep->driver_data) {
value = usb_ep_disable(ep);
ep->driver_data = NULL;
}
} void disable_endpoints(struct usb_composite_dev *cdev,
struct usb_ep *in, struct usb_ep *out)
{
disable_ep(cdev, in);
disable_ep(cdev, out);
} /*-------------------------------------------------------------------------*/ static int __init
sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_sourcesink *ss = func_to_ss(f);
int id; id = usb_interface_id(c, f);
if (id < 0)
return id;
source_sink_intf.bInterfaceNumber = id; ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
if (!ss->in_ep) {
autoconf_fail:
return -ENODEV;
}
ss->in_ep->driver_data = cdev; /* claim */ ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
if (!ss->out_ep)
goto autoconf_fail;
ss->out_ep->driver_data = cdev; /* claim */ /* support high speed hardware */
if (gadget_is_dualspeed(c->cdev->gadget)) {
hs_source_desc.bEndpointAddress =
fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
f->hs_descriptors = hs_source_sink_descs;
} return 0;
} static void
sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
{
kfree(func_to_ss(f));
} static void disable_source_sink(struct f_sourcesink *ss)
{
struct usb_composite_dev *cdev; cdev = ss->function.config->cdev;
disable_endpoints(cdev, ss->in_ep, ss->out_ep);//就是disable了in和out
} static int
enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
{
int result = 0;
struct usb_ep *ep; /* one endpoint writes (sources) zeroes IN (to the host) */
ep = ss->in_ep;
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
if (result)
return result;
result = usb_ep_enable(ep);
if (result < 0)
return result;
ep->driver_data = ss; /* one endpoint reads (sinks) anything OUT (from the host) */
ep = ss->out_ep;
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
if (result)
goto fail;
result = usb_ep_enable(ep);
if (result < 0)
goto fail;
ep->driver_data = ss; return result; fail:
ep = ss->in_ep;
usb_ep_disable(ep);
ep->driver_data = NULL; return result;
} static int sourcesink_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
struct f_sourcesink *ss = func_to_ss(f);
struct usb_composite_dev *cdev = f->config->cdev; /* we know alt is zero */
if (ss->in_ep->driver_data)
disable_source_sink(ss);
return enable_source_sink(cdev, ss);
} static void sourcesink_disable(struct usb_function *f)
{
struct f_sourcesink *ss = func_to_ss(f); disable_source_sink(ss);
} /*-------------------------------------------------------------------------*/ static struct f_sourcesink *ss; static int __init sourcesink_bind_config(struct usb_configuration *c)
{
int status; ss = kzalloc(sizeof *ss, GFP_KERNEL);
if (!ss)
return -ENOMEM; init_completion(&ss->gdt_completion); ss->function.name = "source/sink";
ss->function.descriptors = fs_source_sink_descs;
ss->function.bind = sourcesink_bind;
ss->function.unbind = sourcesink_unbind;
ss->function.set_alt = sourcesink_set_alt;
ss->function.disable = sourcesink_disable; status = usb_add_function(c, &ss->function);
if (status)
kfree(ss);
return status;
} static int sourcesink_setup(struct usb_configuration *c,
const struct usb_ctrlrequest *ctrl)
{
return 0;
} static struct usb_configuration sourcesink_driver = {
.label = "source/sink",
.strings = sourcesink_strings,
.setup = sourcesink_setup,
.bConfigurationValue = 3,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
/* .iConfiguration = DYNAMIC */
}; /**
* sourcesink_add - add a source/sink testing configuration to a device
* @cdev: the device to support the configuration
*/
static int __init sourcesink_add(struct usb_composite_dev *cdev)
{
int id; /* allocate string ID(s) */
id = usb_string_id(cdev);
if (id < 0)
return id;
strings_sourcesink[0].id = id; source_sink_intf.iInterface = id;
sourcesink_driver.iConfiguration = id; return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config);
} struct gadget_misc
{
struct miscdevice miscdevp;
}; static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
{
int status = req->status; switch (status) { case 0: /* normal completion? */ case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
if (ep == ss->out_ep)
{
memset(ss->data, 0, BUFLEN);
memcpy(ss->data, req->buf, req->actual);
ss->actual = req->actual;
}
break; case -EOVERFLOW:
default:
case -EREMOTEIO:
break;
}
//没有继续
free_ep_req(ep, req);
complete(&ss->gdt_completion);
} static int gadget_transfer_open(struct inode *inode, struct file *filp)
{
return 0;
} static ssize_t gadget_transfer_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos)
{
struct usb_request *req;
int ret; req = alloc_ep_req(ss->out_ep);
if (!req)
{
ret = -ENOMEM;
goto fail;
} req->complete = source_sink_complete; ret = usb_ep_queue(ss->out_ep, req, GFP_ATOMIC);
if (ret) {
free_ep_req(ss->out_ep, req); goto fail;
} wait_for_completion(&ss->gdt_completion); ss->actual = (count < ss->actual) ? count : ss->actual;
if (copy_to_user (buf, ss->data, ss->actual)) //拷贝读取的数据到用户空间
{
ret = -EFAULT;
goto fail;
} return ss->actual; fail:
return ret;
} static ssize_t gadget_transfer_write(struct file *filp, const char __user * buf, size_t count, loff_t * f_pos)
{
struct usb_request *req;
int ret; req = alloc_ep_req(ss->in_ep);
if (!req)
{
return -ENOMEM;
} req->length = (count < BUFLEN) ? count : BUFLEN; if (copy_from_user (req->buf, buf, req->length)) //拷贝读取的数据到用户空间
{
ret = -EFAULT;
goto fail;
} req->complete = source_sink_complete; ret = usb_ep_queue(ss->in_ep, req, GFP_ATOMIC);
if (ret)
{
goto fail;
} wait_for_completion(&ss->gdt_completion); return req->actual; fail:
free_ep_req(ss->in_ep, req); return ret;
} static int gadget_transfer_release(struct inode *inode, struct file *filp)
{
return 0;
} static struct file_operations gadget_transfer_fops = {
owner:THIS_MODULE,
open:gadget_transfer_open,
read:gadget_transfer_read,
write:gadget_transfer_write,
release:gadget_transfer_release,
}; static struct miscdevice gadget_transfer_misc = {
MISC_DYNAMIC_MINOR,
"gadget_transfer",
&gadget_transfer_fops,
}; /*-------------------------------------------------------------------------*/ static int __init gadget_transfer_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
int id;
int ret = 0; ret = misc_register(&gadget_transfer_misc);
if (ret)
{
goto fail_reg;
} //各字符串描述符的引索
id = usb_string_id(cdev);//这个东西之前有说过,就是cdev->next_string_id++返回,怕id冲突
if (id < 0)
return id;
strings_dev[STRING_MANUFACTURER_IDX].id = id;
device_desc.iManufacturer = id; id = usb_string_id(cdev);
if (id < 0)
return id;
strings_dev[STRING_PRODUCT_IDX].id = id;
device_desc.iProduct = id; id = usb_string_id(cdev);
if (id < 0)
return id;
strings_dev[STRING_SERIAL_IDX].id = id;
device_desc.iSerialNumber = id; sourcesink_add(cdev); device_desc.bcdDevice = cpu_to_le16(0x0200 + 0x12); snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name); fail_reg: return 0;
} static int gadget_transfer_unbind(struct usb_composite_dev *cdev)
{
misc_deregister(&gadget_transfer_misc); return 0;
} static struct usb_composite_driver gadget_transfer_driver = {
.name = "gadget_transfer",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_SUPER,
.unbind = gadget_transfer_unbind,
}; MODULE_LICENSE("GPL"); static int __init init(void)
{
return usb_composite_probe(&gadget_transfer_driver, gadget_transfer_bind);
}
module_init(init); static void __exit cleanup(void)
{
usb_composite_unregister(&gadget_transfer_driver);
}
module_exit(cleanup);

usb-skeleton.c //linux-2.6.18 就改了

//#define USB_SKEL_VENDOR_ID    0x0ff0
//#define USB_SKEL_PRODUCT_ID    0x0ff0

/*
* USB Skeleton driver - 2.0
*
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
*
* This program 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, version 2.
*
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
* but has been rewritten to be easy to read and use, as no locks are now
* needed anymore.
*
*/ #include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h> /* Define these values to match your devices */
#define USB_SKEL_VENDOR_ID 0x0ff0
#define USB_SKEL_PRODUCT_ID 0x0ff0 /* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table); /* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192 /* our private defines. if this grows any larger, use your own .h file */
#define MAX_TRANSFER ( PAGE_SIZE - 512 )
#define WRITES_IN_FLIGHT 8 /* Structure to hold all of our device specific stuff */
struct usb_skel {
struct usb_device * udev; /* the usb device for this device */
struct usb_interface * interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
unsigned char * bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
struct kref kref;
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref) static struct usb_driver skel_driver; static void skel_delete(struct kref *kref)
{
struct usb_skel *dev = to_skel_dev(kref); usb_put_dev(dev->udev);
kfree (dev->bulk_in_buffer);
kfree (dev);
} static int skel_open(struct inode *inode, struct file *file)
{
struct usb_skel *dev;
struct usb_interface *interface;
int subminor;
int retval = 0; subminor = iminor(inode); interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
goto exit;
} dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
} /* increment our usage count for the device */
kref_get(&dev->kref); /* save our object in the file's private structure */
file->private_data = dev; exit:
return retval;
} static int skel_release(struct inode *inode, struct file *file)
{
struct usb_skel *dev; dev = (struct usb_skel *)file->private_data;
if (dev == NULL)
return -ENODEV; /* decrement the count on our device */
kref_put(&dev->kref, skel_delete);
return 0;
} static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
int retval = 0;
int bytes_read; dev = (struct usb_skel *)file->private_data; /* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&bytes_read, 10000); memset(buffer, 0, sizeof(buffer)); /* if the read was successful, copy the data to userspace */
if (!retval) {
if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
retval = -EFAULT;
else
retval = bytes_read;
} return retval;
} static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_skel *dev; dev = (struct usb_skel *)urb->context; /* sync/async unlink faults aren't errors */
if (urb->status &&
!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
} /* free up our allocated buffer */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
up(&dev->limit_sem);
} static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
int retval = 0;
struct urb *urb = NULL;
char *buf = NULL;
size_t writesize = min(count, (size_t)MAX_TRANSFER); dev = (struct usb_skel *)file->private_data; /* verify that we actually have some data to write */
if (count == 0)
goto exit; /* limit the number of URBs in flight to stop a user from using up all RAM */
if (down_interruptible(&dev->limit_sem)) {
retval = -ERESTARTSYS;
goto exit;
} /* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
} buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
} if (copy_from_user(buf, user_buffer, writesize)) {
retval = -EFAULT;
goto error;
} /* initialize the urb properly */
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, writesize, skel_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
} /* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb); exit:
return writesize; error:
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
usb_free_urb(urb);
up(&dev->limit_sem);
return retval;
} static struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
}; /*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver skel_class = {
.name = "skel%d",
.fops = &skel_fops,
.minor_base = USB_SKEL_MINOR_BASE,
}; static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_skel *dev = NULL;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
int i;
int retval = -ENOMEM; /* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
err("Out of memory");
goto error;
}
kref_init(&dev->kref);
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface; /* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc; if (!dev->bulk_in_endpointAddr &&
((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
== USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
err("Could not allocate bulk_in_buffer");
goto error;
}
} if (!dev->bulk_out_endpointAddr &&
((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
== USB_DIR_OUT) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
}
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
err("Could not find both bulk-in and bulk-out endpoints");
goto error;
} /* save our data pointer in this interface device */
usb_set_intfdata(interface, dev); /* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &skel_class);
if (retval) {
/* something prevented us from registering this driver */
err("Not able to get a minor for this device.");
usb_set_intfdata(interface, NULL);
goto error;
} /* let the user know what node this device is now attached to */
info("USB Skeleton device now attached to USBSkel-%d", interface->minor);
return 0; error:
if (dev)
kref_put(&dev->kref, skel_delete);
return retval;
} static void skel_disconnect(struct usb_interface *interface)
{
struct usb_skel *dev;
int minor = interface->minor; /* prevent skel_open() from racing skel_disconnect() */
lock_kernel(); dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL); /* give back our minor */
usb_deregister_dev(interface, &skel_class); unlock_kernel(); /* decrement our usage count */
kref_put(&dev->kref, skel_delete); info("USB Skeleton #%d now disconnected", minor);
} static struct usb_driver skel_driver = {
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.id_table = skel_table,
}; static int __init usb_skel_init(void)
{
int result; /* register this driver with the USB subsystem */
result = usb_register(&skel_driver);
if (result)
err("usb_register failed. Error number %d", result); return result;
} static void __exit usb_skel_exit(void)
{
/* deregister this driver with the USB subsystem */
usb_deregister(&skel_driver);
} module_init (usb_skel_init);
module_exit (usb_skel_exit); MODULE_LICENSE("GPL");

调试

板子执行

有些答应打印是我加的,不要管,还有我的内核usb这块什么都没选,所以加载的多。

有gadget_transfer设备文件

Windows的提示

虚拟机有0ff0:0ff0 usddevice

在虚拟机装载

板子提示

虚拟机

有个skel0 设备文件

虚拟机执行

如果板子不动作,最后

现在执行cat /dev/skel0

板子执行

虚拟机

反过来

板子读,虚拟机写

当你拔去usb是你会发现/dev/skel0消失

基本就这样,下期会回到我的udc驱动上来,下期再见!

[置顶] 自娱自乐6之Linux gadget驱动5(自编gadget驱动,包涵与之通讯的主机usb驱动,已调试通过)的更多相关文章

  1. [置顶] 自娱自乐7之Linux UDC驱动2(自编udc驱动,现完成枚举过程,从驱动代码分析枚举过程)

    花了半个月,才搞定驱动中的枚举部分,现在说linux的枚举,windows可能有差别. 代码我会贴在后面,现在只是实现枚举,你可能对代码不感兴趣,我就不分析代码了,你可以看看 在<自娱自乐1&g ...

  2. [置顶] 自娱自乐1之Linux UDC驱动(形式模板)

    首先,我不是做驱动的开发人员.所以只能用自娱自乐来表示我的行为. 我不知道udc和gadget驱动是不是冷门的驱动,资料真是不多.我之前买了一本书,上面说到这些,就教你如何调试已写好的驱动.这样也可以 ...

  3. [置顶] 学习鸟哥的Linux私房菜笔记(6)——过滤器、输入输出及管道

    一.过滤器 Linux中的应用工具分为三种: 交互工具 过滤器 编辑器 能够接受数据,过滤再输出的工具,称之为过滤器 对过滤器和进程,存在着输入源与输出对象 二.输入.输出.重定向 输入:过滤器的数据 ...

  4. [置顶] getopt_long函数基本用法-linux

    一.感性认识: [c-sharp]  view plain copy   #include <stdio.h> #include <getopt.h> char * l_opt ...

  5. ahk之路:利用ahk在window7下实现窗口置顶

    操作系统:win7 64位 ahk版本:autohotkey_L1.1.24.03 今天安装了AutoHotkey_1.1.24.03.SciTE.PuloversMacroCreator,重新开始我 ...

  6. [自娱自乐] 3、超声波测距模块DIY笔记(三)

    前言 上一节我们已经研究了超声波接收模块并自己设计了一个超声波接收模块,在此基础上又尝试用单片机加反相器构成生成40KHz的超声波发射电路,可是发现采用这种设计的发射电路存在严重的发射功率太低问题,对 ...

  7. 在UWP中页面滑动导航栏置顶

    最近在研究掌上英雄联盟,主要是用来给自己看新闻,顺便copy个界面改一下段位装装逼,可是在我copy的时候发现这个东西 当你滑动到一定距离的时候导航栏会置顶不动,这个特性在微博和淘宝都有,我看了@ms ...

  8. WinFrom窗体始终置顶

    调用WindowsAPI使窗体始终保持置顶效果,不被其他窗体遮盖: [DllImport("user32.dll", CharSet = CharSet.Auto)] privat ...

  9. winform窗体置顶

    winform窗体置顶 金刚 winform 置顶 今天做了一个winform小工具.需要设置置顶功能. 网上找了下,发现百度真的很垃圾... 还是必应靠谱些. 找到一个可以链接. https://s ...

随机推荐

  1. EntityFramework+Autofac+MVC+EasyUI 搭建公司基本服务项目

    去年年底用了2个星期的时间搭建了 这套框架,从ORM,IOC,MVC,EasyUI都仔细的研究了下,还有日志,异常等等.mvc 我已经开发过很多项目了,我就觉得自己写套框架,看看自己的水平如何.欢迎大 ...

  2. 深入浅出畅谈Zigbee

    ZigBee采用802.15.4标准作为其对等通信的基础.该标准由ZigBee联盟(ZigBee Alliance)开发并管理.ZigBee Alliance是一家投资于该标准并在无线领域进行推广的联 ...

  3. VC内存溢出一例 –- 调用约定不一致 (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE)

    VC (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE) 问题记录 VC内存溢出一例 –- 调用约定不一致 (_CRT_DEBUGGER_HOOK(_CRT_DE ...

  4. linux系统监控常用工具

    linux系统监控常用工具 一.系统核心工具包(coreutils) 1./bin/df 报告系统的磁盘空间用量 df -h  显示磁盘分区fdisk -l 2./bin/uname 显示系统信息 u ...

  5. hdu 1181 变形课(dfs)

    Problem Description 呃......变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个 ...

  6. OpenCms创建站点过程图解——献给OpenCms的刚開始学习的人们

    非常多人都听说了OpenCms,知道了它的强大,索性的下载安装了,最终见到了久违OpenCms,看到了它简洁的界面,欣喜过后却不免一脸茫然,这个东西怎么用,我怎么用它来建站,从哪開始,无从下手,找资料 ...

  7. 线上操作使用tmux提高工作效率

    对于常常在线上操作的人来说有一种烦恼,就是在操作过程中,有事离开了一下,电脑自己主动睡眠了.然后网络断开连接.这时候任务就要又一次跑.非常烦恼. tmux能够解决问题. tmux能够看成虚拟屏幕,不受 ...

  8. RCTF Re300 Writeup

    发现一篇写得更好的:http://insight-labs.org/?p=2009  程序要求输入一个flag.拿ida加载后,发现是Upx壳,脱壳后加载入ida进行分析.定位到输入flag的地方,如 ...

  9. Cassandra - Non-system keyspaces don't have the same replication settings, effective ownership information is meaningless

    In cassandra 2.1.4, if you run "nodetool status" without any keyspace specified, you will ...

  10. 根据树父子ID拼接无限极树结构表的名称

    declare @c varchar(50)set @c='572a3d51-ef7a-459e-a5cd-ebf0fca51e8b' --能查出来呀 你试试,我试一下,好像可以啦谢谢 declare ...