zoukankan      html  css  js  c++  java
  • [置顶] 自娱自乐6之Linux gadget驱动5(自编gadget驱动,包涵与之通讯的主机usb驱动,已调试通过)

    这个代码调试,你首先要保证你的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驱动上来,下期再见!


  • 相关阅读:
    linux安装及入门
    20165103学习基础和C语言基础调查
    20165103 我期望的师生关系
    自旋锁,偏向锁,轻量级锁 和 重量级锁
    volatile的使用及其原理
    (PASS)什么是原子性和原子性操作?
    Linux操作系统 和 Windows操作系统 的区别
    Linux常用命令大全(很全面)
    CAS机制总结
    CAS -- ABA问题的解决方案
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3289841.html
Copyright © 2011-2022 走看看