usb: gadget: dummy_hcd: add setup / cleanup of multiple HW intances

This patch creates & adds multiple instances of the HCD and UDC. We have
a new module option "num" which says how many emulated UDCs + HCDs we
want. The default value is one and currently the maximum is one as well.
This will change soon.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Sebastian Andrzej Siewior 2012-10-29 18:09:55 +01:00 committed by Felipe Balbi
parent b2113136a5
commit c7a1db457b

View File

@ -63,16 +63,20 @@ MODULE_LICENSE("GPL");
struct dummy_hcd_module_parameters { struct dummy_hcd_module_parameters {
bool is_super_speed; bool is_super_speed;
bool is_high_speed; bool is_high_speed;
unsigned int num;
}; };
static struct dummy_hcd_module_parameters mod_data = { static struct dummy_hcd_module_parameters mod_data = {
.is_super_speed = false, .is_super_speed = false,
.is_high_speed = true, .is_high_speed = true,
.num = 1,
}; };
module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* gadget side driver data structres */ /* gadget side driver data structres */
@ -2634,6 +2638,7 @@ static struct platform_device *the_hcd_pdev[MAX_NUM_UDC];
static int __init init(void) static int __init init(void)
{ {
int retval = -ENOMEM; int retval = -ENOMEM;
int i;
if (usb_disabled()) if (usb_disabled())
return -ENODEV; return -ENODEV;
@ -2641,12 +2646,29 @@ static int __init init(void)
if (!mod_data.is_high_speed && mod_data.is_super_speed) if (!mod_data.is_high_speed && mod_data.is_super_speed)
return -EINVAL; return -EINVAL;
the_hcd_pdev[0] = platform_device_alloc(driver_name, 0); if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) {
if (!the_hcd_pdev[0]) pr_err("Number of emulated UDC must be in range of 1…%d\n",
return retval; MAX_NUM_UDC);
the_udc_pdev[0] = platform_device_alloc(gadget_name, 0); return -EINVAL;
if (!the_udc_pdev[0]) }
goto err_alloc_udc; for (i = 0; i < mod_data.num; i++) {
the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
if (!the_hcd_pdev[i]) {
i--;
while (i >= 0)
platform_device_put(the_hcd_pdev[i--]);
return retval;
}
}
for (i = 0; i < mod_data.num; i++) {
the_udc_pdev[i] = platform_device_alloc(gadget_name, i);
if (!the_udc_pdev[i]) {
i--;
while (i >= 0)
platform_device_put(the_udc_pdev[i--]);
goto err_alloc_udc;
}
}
retval = platform_driver_register(&dummy_hcd_driver); retval = platform_driver_register(&dummy_hcd_driver);
if (retval < 0) if (retval < 0)
@ -2655,9 +2677,15 @@ static int __init init(void)
if (retval < 0) if (retval < 0)
goto err_register_udc_driver; goto err_register_udc_driver;
retval = platform_device_add(the_hcd_pdev[0]); for (i = 0; i < mod_data.num; i++) {
if (retval < 0) retval = platform_device_add(the_hcd_pdev[i]);
goto err_add_hcd; if (retval < 0) {
i--;
while (i >= 0)
platform_device_del(the_hcd_pdev[i--]);
goto err_add_hcd;
}
}
if (!the_controller.hs_hcd || if (!the_controller.hs_hcd ||
(!the_controller.ss_hcd && mod_data.is_super_speed)) { (!the_controller.ss_hcd && mod_data.is_super_speed)) {
/* /*
@ -2667,39 +2695,58 @@ static int __init init(void)
retval = -EINVAL; retval = -EINVAL;
goto err_add_udc; goto err_add_udc;
} }
retval = platform_device_add(the_udc_pdev[0]);
if (retval < 0)
goto err_add_udc; for (i = 0; i < mod_data.num; i++) {
if (!platform_get_drvdata(the_udc_pdev[0])) { retval = platform_device_add(the_udc_pdev[i]);
/* if (retval < 0) {
* The udc was added successfully but its probe function failed i--;
* for some reason. while (i >= 0)
*/ platform_device_del(the_udc_pdev[i]);
retval = -EINVAL; goto err_add_udc;
goto err_probe_udc; }
}
for (i = 0; i < mod_data.num; i++) {
if (!platform_get_drvdata(the_udc_pdev[i])) {
/*
* The udc was added successfully but its probe
* function failed for some reason.
*/
retval = -EINVAL;
goto err_probe_udc;
}
} }
return retval; return retval;
err_probe_udc: err_probe_udc:
platform_device_del(the_udc_pdev[0]); for (i = 0; i < mod_data.num; i++)
platform_device_del(the_udc_pdev[i]);
err_add_udc: err_add_udc:
platform_device_del(the_hcd_pdev[0]); for (i = 0; i < mod_data.num; i++)
platform_device_del(the_hcd_pdev[i]);
err_add_hcd: err_add_hcd:
platform_driver_unregister(&dummy_udc_driver); platform_driver_unregister(&dummy_udc_driver);
err_register_udc_driver: err_register_udc_driver:
platform_driver_unregister(&dummy_hcd_driver); platform_driver_unregister(&dummy_hcd_driver);
err_register_hcd_driver: err_register_hcd_driver:
platform_device_put(the_udc_pdev[0]); for (i = 0; i < mod_data.num; i++)
platform_device_put(the_udc_pdev[i]);
err_alloc_udc: err_alloc_udc:
platform_device_put(the_hcd_pdev[0]); for (i = 0; i < mod_data.num; i++)
platform_device_put(the_hcd_pdev[i]);
return retval; return retval;
} }
module_init(init); module_init(init);
static void __exit cleanup(void) static void __exit cleanup(void)
{ {
platform_device_unregister(the_udc_pdev[0]); int i;
platform_device_unregister(the_hcd_pdev[0]);
for (i = 0; i < mod_data.num; i++) {
platform_device_unregister(the_udc_pdev[i]);
platform_device_unregister(the_hcd_pdev[i]);
}
platform_driver_unregister(&dummy_udc_driver); platform_driver_unregister(&dummy_udc_driver);
platform_driver_unregister(&dummy_hcd_driver); platform_driver_unregister(&dummy_hcd_driver);
} }