#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>

MODULE_LICENSE("GPL");
#define USB_VENDOR_ID  0x18ec 
#define USB_PRODUCT_ID 0x3299
#define MYUSB_MINOR_BASE    250

#define DUMP_USB_INTERFACE_DESCRIPTOR( i ) \
{\
        pr_info("USB_INTERFACE_DESCRIPTOR:\n"); \
        pr_info("-----------------------------\n"); \
        pr_info("bLength: 0x%x\n", i.bLength); \
        pr_info("bDescriptorType: 0x%x\n", i.bDescriptorType); \
        pr_info("bInterfaceNumber: 0x%x\n", i.bInterfaceNumber); \
        pr_info("bAlternateSetting: 0x%x\n", i.bAlternateSetting); \
        pr_info("bNumEndpoints: 0x%x\n", i.bNumEndpoints); \
        pr_info("bInterfaceClass: 0x%x\n", i.bInterfaceClass); \
        pr_info("bInterfaceSubClass: 0x%x\n", i.bInterfaceSubClass); \
        pr_info("bInterfaceProtocol: 0x%x\n", i.bInterfaceProtocol); \
        pr_info("iInterface: 0x%x\n", i.iInterface); \
        pr_info("\n"); \
}

#define DUMP_USB_ENDPOINT_DESCRIPTOR( e ) \
{\
        pr_info("USB_ENDPOINT_DESCRIPTOR:\n"); \
        pr_info("------------------------\n"); \
        pr_info("bLength: 0x%x\n", e.bLength); \
        pr_info("bDescriptorType: 0x%x\n", e.bDescriptorType); \
        pr_info("bEndPointAddress: 0x%x\n", e.bEndpointAddress); \
        pr_info("bmAttributes: 0x%x\n", e.bmAttributes); \
        pr_info("wMaxPacketSize: 0x%x\n", e.wMaxPacketSize); \
        pr_info("bInterval: 0x%x\n", e.bInterval); \
        pr_info("\n"); \
}


const struct usb_device_id usb_table[] = {
    { USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID) },
    { }
};
MODULE_DEVICE_TABLE(usb, usb_table);

static int myusb_open(struct inode *inode, struct file *file)
{
    pr_info("%s\n", __func__);
    return 0;
}

static int myusb_release(struct inode *inode, struct file *file)
{
    pr_info("%s\n", __func__);
    return 0;
}

static ssize_t myusb_write(struct file *file, const char *user_buffer,
                          size_t count, loff_t *ppos)
{
    pr_info("%s\n", __func__);
    return count;
}

static ssize_t myusb_read(struct file *file, char *buffer, size_t count,
                            loff_t *ppos)
{
    pr_info("%s\n", __func__);
    return 0;
}

static const struct file_operations myusb_fops = {
    .owner = THIS_MODULE,
    .open = myusb_open,
    .release = myusb_release,
    .read = myusb_read,
    .write = myusb_write,
};

static struct usb_class_driver myusb_class = {
    .name = "mydevice%d",
    .fops = &myusb_fops,
    .minor_base = MYUSB_MINOR_BASE,
};

static int usb_probe(struct usb_interface *interface,
                        const struct usb_device_id *id)
{
    unsigned int i;
    unsigned int num_endpoints;
    struct usb_host_interface *iface_desc = interface->cur_altsetting;

    dev_info(&interface->dev, "USB Driver Probed: Vendor ID:%02x\t"
             "Product ID:%02x\n", id->idVendor, id->idProduct);
    num_endpoints = iface_desc->desc.bNumEndpoints;
    DUMP_USB_INTERFACE_DESCRIPTOR(iface_desc->desc);
     for (i = 0; i < num_endpoints; i++) {
          DUMP_USB_ENDPOINT_DESCRIPTOR(iface_desc->endpoint[i].desc);
    }
    return usb_register_dev(interface, &myusb_class);;
}

static void usb_disconnect(struct usb_interface *interface)
{
    usb_deregister_dev(interface, &myusb_class);
    dev_info(&interface->dev, "USB Driver Disconected\n");
}


static struct usb_driver usb_hello_driver = {
    .name = "hello",
    .probe = usb_probe,
    .disconnect = usb_disconnect,
    .id_table = usb_table,
};

module_usb_driver(usb_hello_driver);