#include "hv_drv_UsbErr.h"
#include "hv_drv_UsbCompat.h"
#include "hv_drv_UsbGadgetComposite.h"
#include "hv_vos_Comm.h"

#define szq_del 0
static LIST_HEAD(func_list);

//szq add 
static inline int request_module(const char *name, ...) { return -ENOSYS; }

static struct usb_function_instance *try_get_usb_function_instance(const char *name)
{
    struct usb_function_driver *fd;
    struct usb_function_instance *fi;

    fi = ERR_PTR(-ENOENT);
#if szq_del
    mutex_lock(&func_lock);
#endif
    list_for_each_entry(fd, &func_list, list) {
        if (strcmp(name, fd->name)){
            debug("---got fd name: %s\n",fd->name);
            continue;
        }

        if (!try_module_get(fd->mod)) {
            debug("---err\n");
            fi = ERR_PTR(-EBUSY);
            break;
        }
        fi = fd->alloc_inst();
        
        if (IS_ERR(fi))
            module_put(fd->mod);
        else
            fi->fd = fd;
        break;
    }
#if szq_del
    mutex_unlock(&func_lock);
#endif
    return fi;
}

struct usb_function_instance *usb_get_function_instance(const char *name)
{
    struct usb_function_instance *fi;
    int ret;

    fi = try_get_usb_function_instance(name);
    debug("---usb_get_function_instance: fi at 0x%x, name: %s\n", fi,name);
    if (!IS_ERR(fi))
        return fi;
    ret = PTR_ERR(fi);
    if (ret != -ENOENT)
        return fi;
    ret = request_module("usbfunc:%s", name);
    if (ret < 0)
        return ERR_PTR(ret);
    return try_get_usb_function_instance(name);
}

struct usb_function *usb_get_function(struct usb_function_instance *fi)
{
    struct usb_function *f;

    f = fi->fd->alloc_func(fi);
    if (IS_ERR(f))
        return f;
#if szq_del
    f->fi = fi;
#endif
    return f;
}

void usb_put_function_instance(struct usb_function_instance *fi)
{
#if szq_del    
    struct module *mod;

    if (!fi)
        return;

    mod = fi->fd->mod;
    fi->free_func_inst(fi);
    module_put(mod);
#endif    
}

void usb_put_function(struct usb_function *f)
{
    if (!f)
        return;
#if szq_del
    f->free_func(f);
#endif
}

int usb_function_register(struct usb_function_driver *newf)
{
    struct usb_function_driver *fd;
    int ret;

    ret = -EEXIST;

    mutex_lock(&func_lock);
    list_for_each_entry(fd, &func_list, list) {
        if (!strcmp(fd->name, newf->name)){
            debug("---err, not found func_list\n");
            goto out;
        }
    }
    ret = 0;
    list_add_tail(&newf->list, &func_list);
    debug("---newf:0x%x  newf->list:0x%x name:%s\n", newf, &newf->list,newf->name);
out:
    mutex_unlock(&func_lock);
    return ret;
}

void usb_function_unregister(struct usb_function_driver *fd)
{
#if szq_del
    mutex_lock(&func_lock);
#endif
    list_del(&fd->list);
#if szq_del
    mutex_unlock(&func_lock);
#endif
}
