aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/dummy_hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/dummy_hcd.c')
-rw-r--r--drivers/usb/gadget/dummy_hcd.c170
1 files changed, 122 insertions, 48 deletions
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 0f7541be28f3..95d584dbed13 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -63,16 +63,20 @@ MODULE_LICENSE("GPL");
63struct dummy_hcd_module_parameters { 63struct dummy_hcd_module_parameters {
64 bool is_super_speed; 64 bool is_super_speed;
65 bool is_high_speed; 65 bool is_high_speed;
66 unsigned int num;
66}; 67};
67 68
68static struct dummy_hcd_module_parameters mod_data = { 69static struct dummy_hcd_module_parameters mod_data = {
69 .is_super_speed = false, 70 .is_super_speed = false,
70 .is_high_speed = true, 71 .is_high_speed = true,
72 .num = 1,
71}; 73};
72module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); 74module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
73MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); 75MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
74module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); 76module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
75MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); 77MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
78module_param_named(num, mod_data.num, uint, S_IRUGO);
79MODULE_PARM_DESC(num, "number of emulated controllers");
76/*-------------------------------------------------------------------------*/ 80/*-------------------------------------------------------------------------*/
77 81
78/* gadget side driver data structres */ 82/* gadget side driver data structres */
@@ -238,8 +242,6 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
238 return container_of(dev, struct dummy, gadget.dev); 242 return container_of(dev, struct dummy, gadget.dev);
239} 243}
240 244
241static struct dummy the_controller;
242
243/*-------------------------------------------------------------------------*/ 245/*-------------------------------------------------------------------------*/
244 246
245/* SLAVE/GADGET SIDE UTILITY ROUTINES */ 247/* SLAVE/GADGET SIDE UTILITY ROUTINES */
@@ -973,9 +975,10 @@ static void init_dummy_udc_hw(struct dummy *dum)
973 975
974static int dummy_udc_probe(struct platform_device *pdev) 976static int dummy_udc_probe(struct platform_device *pdev)
975{ 977{
976 struct dummy *dum = &the_controller; 978 struct dummy *dum;
977 int rc; 979 int rc;
978 980
981 dum = *((void **)dev_get_platdata(&pdev->dev));
979 dum->gadget.name = gadget_name; 982 dum->gadget.name = gadget_name;
980 dum->gadget.ops = &dummy_ops; 983 dum->gadget.ops = &dummy_ops;
981 dum->gadget.max_speed = USB_SPEED_SUPER; 984 dum->gadget.max_speed = USB_SPEED_SUPER;
@@ -2398,10 +2401,13 @@ static int dummy_h_get_frame(struct usb_hcd *hcd)
2398 2401
2399static int dummy_setup(struct usb_hcd *hcd) 2402static int dummy_setup(struct usb_hcd *hcd)
2400{ 2403{
2404 struct dummy *dum;
2405
2406 dum = *((void **)dev_get_platdata(hcd->self.controller));
2401 hcd->self.sg_tablesize = ~0; 2407 hcd->self.sg_tablesize = ~0;
2402 if (usb_hcd_is_primary_hcd(hcd)) { 2408 if (usb_hcd_is_primary_hcd(hcd)) {
2403 the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); 2409 dum->hs_hcd = hcd_to_dummy_hcd(hcd);
2404 the_controller.hs_hcd->dum = &the_controller; 2410 dum->hs_hcd->dum = dum;
2405 /* 2411 /*
2406 * Mark the first roothub as being USB 2.0. 2412 * Mark the first roothub as being USB 2.0.
2407 * The USB 3.0 roothub will be registered later by 2413 * The USB 3.0 roothub will be registered later by
@@ -2410,8 +2416,8 @@ static int dummy_setup(struct usb_hcd *hcd)
2410 hcd->speed = HCD_USB2; 2416 hcd->speed = HCD_USB2;
2411 hcd->self.root_hub->speed = USB_SPEED_HIGH; 2417 hcd->self.root_hub->speed = USB_SPEED_HIGH;
2412 } else { 2418 } else {
2413 the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); 2419 dum->ss_hcd = hcd_to_dummy_hcd(hcd);
2414 the_controller.ss_hcd->dum = &the_controller; 2420 dum->ss_hcd->dum = dum;
2415 hcd->speed = HCD_USB3; 2421 hcd->speed = HCD_USB3;
2416 hcd->self.root_hub->speed = USB_SPEED_SUPER; 2422 hcd->self.root_hub->speed = USB_SPEED_SUPER;
2417 } 2423 }
@@ -2524,11 +2530,13 @@ static struct hc_driver dummy_hcd = {
2524 2530
2525static int dummy_hcd_probe(struct platform_device *pdev) 2531static int dummy_hcd_probe(struct platform_device *pdev)
2526{ 2532{
2533 struct dummy *dum;
2527 struct usb_hcd *hs_hcd; 2534 struct usb_hcd *hs_hcd;
2528 struct usb_hcd *ss_hcd; 2535 struct usb_hcd *ss_hcd;
2529 int retval; 2536 int retval;
2530 2537
2531 dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); 2538 dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
2539 dum = *((void **)dev_get_platdata(&pdev->dev));
2532 2540
2533 if (!mod_data.is_super_speed) 2541 if (!mod_data.is_super_speed)
2534 dummy_hcd.flags = HCD_USB2; 2542 dummy_hcd.flags = HCD_USB2;
@@ -2561,7 +2569,7 @@ dealloc_usb2_hcd:
2561 usb_remove_hcd(hs_hcd); 2569 usb_remove_hcd(hs_hcd);
2562put_usb2_hcd: 2570put_usb2_hcd:
2563 usb_put_hcd(hs_hcd); 2571 usb_put_hcd(hs_hcd);
2564 the_controller.hs_hcd = the_controller.ss_hcd = NULL; 2572 dum->hs_hcd = dum->ss_hcd = NULL;
2565 return retval; 2573 return retval;
2566} 2574}
2567 2575
@@ -2579,8 +2587,8 @@ static int dummy_hcd_remove(struct platform_device *pdev)
2579 usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); 2587 usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2580 usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); 2588 usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2581 2589
2582 the_controller.hs_hcd = NULL; 2590 dum->hs_hcd = NULL;
2583 the_controller.ss_hcd = NULL; 2591 dum->ss_hcd = NULL;
2584 2592
2585 return 0; 2593 return 0;
2586} 2594}
@@ -2627,13 +2635,15 @@ static struct platform_driver dummy_hcd_driver = {
2627}; 2635};
2628 2636
2629/*-------------------------------------------------------------------------*/ 2637/*-------------------------------------------------------------------------*/
2630 2638#define MAX_NUM_UDC 2
2631static struct platform_device *the_udc_pdev; 2639static struct platform_device *the_udc_pdev[MAX_NUM_UDC];
2632static struct platform_device *the_hcd_pdev; 2640static struct platform_device *the_hcd_pdev[MAX_NUM_UDC];
2633 2641
2634static int __init init(void) 2642static int __init init(void)
2635{ 2643{
2636 int retval = -ENOMEM; 2644 int retval = -ENOMEM;
2645 int i;
2646 struct dummy *dum[MAX_NUM_UDC];
2637 2647
2638 if (usb_disabled()) 2648 if (usb_disabled())
2639 return -ENODEV; 2649 return -ENODEV;
@@ -2641,65 +2651,129 @@ static int __init init(void)
2641 if (!mod_data.is_high_speed && mod_data.is_super_speed) 2651 if (!mod_data.is_high_speed && mod_data.is_super_speed)
2642 return -EINVAL; 2652 return -EINVAL;
2643 2653
2644 the_hcd_pdev = platform_device_alloc(driver_name, -1); 2654 if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) {
2645 if (!the_hcd_pdev) 2655 pr_err("Number of emulated UDC must be in range of 1…%d\n",
2646 return retval; 2656 MAX_NUM_UDC);
2647 the_udc_pdev = platform_device_alloc(gadget_name, -1); 2657 return -EINVAL;
2648 if (!the_udc_pdev) 2658 }
2649 goto err_alloc_udc; 2659
2660 for (i = 0; i < mod_data.num; i++) {
2661 the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
2662 if (!the_hcd_pdev[i]) {
2663 i--;
2664 while (i >= 0)
2665 platform_device_put(the_hcd_pdev[i--]);
2666 return retval;
2667 }
2668 }
2669 for (i = 0; i < mod_data.num; i++) {
2670 the_udc_pdev[i] = platform_device_alloc(gadget_name, i);
2671 if (!the_udc_pdev[i]) {
2672 i--;
2673 while (i >= 0)
2674 platform_device_put(the_udc_pdev[i--]);
2675 goto err_alloc_udc;
2676 }
2677 }
2678 for (i = 0; i < mod_data.num; i++) {
2679 dum[i] = kzalloc(sizeof(struct dummy), GFP_KERNEL);
2680 if (!dum[i])
2681 goto err_add_pdata;
2682 retval = platform_device_add_data(the_hcd_pdev[i], &dum[i],
2683 sizeof(void *));
2684 if (retval)
2685 goto err_add_pdata;
2686 retval = platform_device_add_data(the_udc_pdev[i], &dum[i],
2687 sizeof(void *));
2688 if (retval)
2689 goto err_add_pdata;
2690 }
2650 2691
2651 retval = platform_driver_register(&dummy_hcd_driver); 2692 retval = platform_driver_register(&dummy_hcd_driver);
2652 if (retval < 0) 2693 if (retval < 0)
2653 goto err_register_hcd_driver; 2694 goto err_add_pdata;
2654 retval = platform_driver_register(&dummy_udc_driver); 2695 retval = platform_driver_register(&dummy_udc_driver);
2655 if (retval < 0) 2696 if (retval < 0)
2656 goto err_register_udc_driver; 2697 goto err_register_udc_driver;
2657 2698
2658 retval = platform_device_add(the_hcd_pdev); 2699 for (i = 0; i < mod_data.num; i++) {
2659 if (retval < 0) 2700 retval = platform_device_add(the_hcd_pdev[i]);
2660 goto err_add_hcd; 2701 if (retval < 0) {
2661 if (!the_controller.hs_hcd || 2702 i--;
2662 (!the_controller.ss_hcd && mod_data.is_super_speed)) { 2703 while (i >= 0)
2663 /* 2704 platform_device_del(the_hcd_pdev[i--]);
2664 * The hcd was added successfully but its probe function failed 2705 goto err_add_hcd;
2665 * for some reason. 2706 }
2666 */
2667 retval = -EINVAL;
2668 goto err_add_udc;
2669 } 2707 }
2670 retval = platform_device_add(the_udc_pdev); 2708 for (i = 0; i < mod_data.num; i++) {
2671 if (retval < 0) 2709 if (!dum[i]->hs_hcd ||
2672 goto err_add_udc; 2710 (!dum[i]->ss_hcd && mod_data.is_super_speed)) {
2673 if (!platform_get_drvdata(the_udc_pdev)) { 2711 /*
2674 /* 2712 * The hcd was added successfully but its probe
2675 * The udc was added successfully but its probe function failed 2713 * function failed for some reason.
2676 * for some reason. 2714 */
2677 */ 2715 retval = -EINVAL;
2678 retval = -EINVAL; 2716 goto err_add_udc;
2679 goto err_probe_udc; 2717 }
2718 }
2719
2720 for (i = 0; i < mod_data.num; i++) {
2721 retval = platform_device_add(the_udc_pdev[i]);
2722 if (retval < 0) {
2723 i--;
2724 while (i >= 0)
2725 platform_device_del(the_udc_pdev[i]);
2726 goto err_add_udc;
2727 }
2728 }
2729
2730 for (i = 0; i < mod_data.num; i++) {
2731 if (!platform_get_drvdata(the_udc_pdev[i])) {
2732 /*
2733 * The udc was added successfully but its probe
2734 * function failed for some reason.
2735 */
2736 retval = -EINVAL;
2737 goto err_probe_udc;
2738 }
2680 } 2739 }
2681 return retval; 2740 return retval;
2682 2741
2683err_probe_udc: 2742err_probe_udc:
2684 platform_device_del(the_udc_pdev); 2743 for (i = 0; i < mod_data.num; i++)
2744 platform_device_del(the_udc_pdev[i]);
2685err_add_udc: 2745err_add_udc:
2686 platform_device_del(the_hcd_pdev); 2746 for (i = 0; i < mod_data.num; i++)
2747 platform_device_del(the_hcd_pdev[i]);
2687err_add_hcd: 2748err_add_hcd:
2688 platform_driver_unregister(&dummy_udc_driver); 2749 platform_driver_unregister(&dummy_udc_driver);
2689err_register_udc_driver: 2750err_register_udc_driver:
2690 platform_driver_unregister(&dummy_hcd_driver); 2751 platform_driver_unregister(&dummy_hcd_driver);
2691err_register_hcd_driver: 2752err_add_pdata:
2692 platform_device_put(the_udc_pdev); 2753 for (i = 0; i < mod_data.num; i++)
2754 kfree(dum[i]);
2755 for (i = 0; i < mod_data.num; i++)
2756 platform_device_put(the_udc_pdev[i]);
2693err_alloc_udc: 2757err_alloc_udc:
2694 platform_device_put(the_hcd_pdev); 2758 for (i = 0; i < mod_data.num; i++)
2759 platform_device_put(the_hcd_pdev[i]);
2695 return retval; 2760 return retval;
2696} 2761}
2697module_init(init); 2762module_init(init);
2698 2763
2699static void __exit cleanup(void) 2764static void __exit cleanup(void)
2700{ 2765{
2701 platform_device_unregister(the_udc_pdev); 2766 int i;
2702 platform_device_unregister(the_hcd_pdev); 2767
2768 for (i = 0; i < mod_data.num; i++) {
2769 struct dummy *dum;
2770
2771 dum = *((void **)dev_get_platdata(&the_udc_pdev[i]->dev));
2772
2773 platform_device_unregister(the_udc_pdev[i]);
2774 platform_device_unregister(the_hcd_pdev[i]);
2775 kfree(dum);
2776 }
2703 platform_driver_unregister(&dummy_udc_driver); 2777 platform_driver_unregister(&dummy_udc_driver);
2704 platform_driver_unregister(&dummy_hcd_driver); 2778 platform_driver_unregister(&dummy_hcd_driver);
2705} 2779}