@@ -37,6 +37,10 @@ static struct bus_type gadget_bus_type;
37
37
* @vbus: for udcs who care about vbus status, this value is real vbus status;
38
38
* for udcs who do not care about vbus status, this value is always true
39
39
* @started: the UDC's started state. True if the UDC had started.
40
+ * @connect_lock: protects udc->vbus, udc->started, gadget->connect, gadget->deactivate related
41
+ * functions. usb_gadget_connect_locked, usb_gadget_disconnect_locked,
42
+ * usb_udc_connect_control_locked, usb_gadget_udc_start_locked, usb_gadget_udc_stop_locked are
43
+ * called with this lock held.
40
44
*
41
45
* This represents the internal data structure which is used by the UDC-class
42
46
* to hold information about udc driver and gadget together.
@@ -48,6 +52,7 @@ struct usb_udc {
48
52
struct list_head list ;
49
53
bool vbus ;
50
54
bool started ;
55
+ struct mutex connect_lock ;
51
56
};
52
57
53
58
static struct class * udc_class ;
@@ -660,17 +665,9 @@ int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
660
665
}
661
666
EXPORT_SYMBOL_GPL (usb_gadget_vbus_disconnect );
662
667
663
- /**
664
- * usb_gadget_connect - software-controlled connect to USB host
665
- * @gadget:the peripheral being connected
666
- *
667
- * Enables the D+ (or potentially D-) pullup. The host will start
668
- * enumerating this gadget when the pullup is active and a VBUS session
669
- * is active (the link is powered).
670
- *
671
- * Returns zero on success, else negative errno.
672
- */
673
- int usb_gadget_connect (struct usb_gadget * gadget )
668
+ /* Internal version of usb_gadget_connect needs to be called with connect_lock held. */
669
+ static int usb_gadget_connect_locked (struct usb_gadget * gadget )
670
+ __must_hold (& gadget - > udc - > connect_lock )
674
671
{
675
672
int ret = 0 ;
676
673
@@ -679,10 +676,12 @@ int usb_gadget_connect(struct usb_gadget *gadget)
679
676
goto out ;
680
677
}
681
678
682
- if (gadget -> deactivated ) {
679
+ if (gadget -> deactivated || ! gadget -> udc -> started ) {
683
680
/*
684
681
* If gadget is deactivated we only save new state.
685
682
* Gadget will be connected automatically after activation.
683
+ *
684
+ * udc first needs to be started before gadget can be pulled up.
686
685
*/
687
686
gadget -> connected = true;
688
687
goto out ;
@@ -697,22 +696,32 @@ int usb_gadget_connect(struct usb_gadget *gadget)
697
696
698
697
return ret ;
699
698
}
700
- EXPORT_SYMBOL_GPL (usb_gadget_connect );
701
699
702
700
/**
703
- * usb_gadget_disconnect - software-controlled disconnect from USB host
704
- * @gadget:the peripheral being disconnected
705
- *
706
- * Disables the D+ (or potentially D-) pullup, which the host may see
707
- * as a disconnect (when a VBUS session is active). Not all systems
708
- * support software pullup controls.
701
+ * usb_gadget_connect - software-controlled connect to USB host
702
+ * @gadget:the peripheral being connected
709
703
*
710
- * Following a successful disconnect, invoke the ->disconnect() callback
711
- * for the current gadget driver so that UDC drivers don't need to.
704
+ * Enables the D+ (or potentially D-) pullup. The host will start
705
+ * enumerating this gadget when the pullup is active and a VBUS session
706
+ * is active (the link is powered).
712
707
*
713
708
* Returns zero on success, else negative errno.
714
709
*/
715
- int usb_gadget_disconnect (struct usb_gadget * gadget )
710
+ int usb_gadget_connect (struct usb_gadget * gadget )
711
+ {
712
+ int ret ;
713
+
714
+ mutex_lock (& gadget -> udc -> connect_lock );
715
+ ret = usb_gadget_connect_locked (gadget );
716
+ mutex_unlock (& gadget -> udc -> connect_lock );
717
+
718
+ return ret ;
719
+ }
720
+ EXPORT_SYMBOL_GPL (usb_gadget_connect );
721
+
722
+ /* Internal version of usb_gadget_disconnect needs to be called with connect_lock held. */
723
+ static int usb_gadget_disconnect_locked (struct usb_gadget * gadget )
724
+ __must_hold (& gadget - > udc - > connect_lock )
716
725
{
717
726
int ret = 0 ;
718
727
@@ -724,10 +733,12 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
724
733
if (!gadget -> connected )
725
734
goto out ;
726
735
727
- if (gadget -> deactivated ) {
736
+ if (gadget -> deactivated || ! gadget -> udc -> started ) {
728
737
/*
729
738
* If gadget is deactivated we only save new state.
730
739
* Gadget will stay disconnected after activation.
740
+ *
741
+ * udc should have been started before gadget being pulled down.
731
742
*/
732
743
gadget -> connected = false;
733
744
goto out ;
@@ -747,6 +758,30 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
747
758
748
759
return ret ;
749
760
}
761
+
762
+ /**
763
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
764
+ * @gadget:the peripheral being disconnected
765
+ *
766
+ * Disables the D+ (or potentially D-) pullup, which the host may see
767
+ * as a disconnect (when a VBUS session is active). Not all systems
768
+ * support software pullup controls.
769
+ *
770
+ * Following a successful disconnect, invoke the ->disconnect() callback
771
+ * for the current gadget driver so that UDC drivers don't need to.
772
+ *
773
+ * Returns zero on success, else negative errno.
774
+ */
775
+ int usb_gadget_disconnect (struct usb_gadget * gadget )
776
+ {
777
+ int ret ;
778
+
779
+ mutex_lock (& gadget -> udc -> connect_lock );
780
+ ret = usb_gadget_disconnect_locked (gadget );
781
+ mutex_unlock (& gadget -> udc -> connect_lock );
782
+
783
+ return ret ;
784
+ }
750
785
EXPORT_SYMBOL_GPL (usb_gadget_disconnect );
751
786
752
787
/**
@@ -767,10 +802,11 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
767
802
if (gadget -> deactivated )
768
803
goto out ;
769
804
805
+ mutex_lock (& gadget -> udc -> connect_lock );
770
806
if (gadget -> connected ) {
771
- ret = usb_gadget_disconnect (gadget );
807
+ ret = usb_gadget_disconnect_locked (gadget );
772
808
if (ret )
773
- goto out ;
809
+ goto unlock ;
774
810
775
811
/*
776
812
* If gadget was being connected before deactivation, we want
@@ -780,6 +816,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
780
816
}
781
817
gadget -> deactivated = true;
782
818
819
+ unlock :
820
+ mutex_unlock (& gadget -> udc -> connect_lock );
783
821
out :
784
822
trace_usb_gadget_deactivate (gadget , ret );
785
823
@@ -803,14 +841,16 @@ int usb_gadget_activate(struct usb_gadget *gadget)
803
841
if (!gadget -> deactivated )
804
842
goto out ;
805
843
844
+ mutex_lock (& gadget -> udc -> connect_lock );
806
845
gadget -> deactivated = false;
807
846
808
847
/*
809
848
* If gadget has been connected before deactivation, or became connected
810
849
* while it was being deactivated, we call usb_gadget_connect().
811
850
*/
812
851
if (gadget -> connected )
813
- ret = usb_gadget_connect (gadget );
852
+ ret = usb_gadget_connect_locked (gadget );
853
+ mutex_unlock (& gadget -> udc -> connect_lock );
814
854
815
855
out :
816
856
trace_usb_gadget_activate (gadget , ret );
@@ -1051,12 +1091,13 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
1051
1091
1052
1092
/* ------------------------------------------------------------------------- */
1053
1093
1054
- static void usb_udc_connect_control (struct usb_udc * udc )
1094
+ /* Acquire connect_lock before calling this function. */
1095
+ static void usb_udc_connect_control_locked (struct usb_udc * udc ) __must_hold (& udc - > connect_lock )
1055
1096
{
1056
- if (udc -> vbus )
1057
- usb_gadget_connect (udc -> gadget );
1097
+ if (udc -> vbus && udc -> started )
1098
+ usb_gadget_connect_locked (udc -> gadget );
1058
1099
else
1059
- usb_gadget_disconnect (udc -> gadget );
1100
+ usb_gadget_disconnect_locked (udc -> gadget );
1060
1101
}
1061
1102
1062
1103
/**
@@ -1072,10 +1113,12 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
1072
1113
{
1073
1114
struct usb_udc * udc = gadget -> udc ;
1074
1115
1116
+ mutex_lock (& udc -> connect_lock );
1075
1117
if (udc ) {
1076
1118
udc -> vbus = status ;
1077
- usb_udc_connect_control (udc );
1119
+ usb_udc_connect_control_locked (udc );
1078
1120
}
1121
+ mutex_unlock (& udc -> connect_lock );
1079
1122
}
1080
1123
EXPORT_SYMBOL_GPL (usb_udc_vbus_handler );
1081
1124
@@ -1097,7 +1140,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget,
1097
1140
EXPORT_SYMBOL_GPL (usb_gadget_udc_reset );
1098
1141
1099
1142
/**
1100
- * usb_gadget_udc_start - tells usb device controller to start up
1143
+ * usb_gadget_udc_start_locked - tells usb device controller to start up
1101
1144
* @udc: The UDC to be started
1102
1145
*
1103
1146
* This call is issued by the UDC Class driver when it's about
@@ -1108,8 +1151,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
1108
1151
* necessary to have it powered on.
1109
1152
*
1110
1153
* Returns zero on success, else negative errno.
1154
+ *
1155
+ * Caller should acquire connect_lock before invoking this function.
1111
1156
*/
1112
- static inline int usb_gadget_udc_start (struct usb_udc * udc )
1157
+ static inline int usb_gadget_udc_start_locked (struct usb_udc * udc )
1158
+ __must_hold (& udc - > connect_lock )
1113
1159
{
1114
1160
int ret ;
1115
1161
@@ -1126,7 +1172,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
1126
1172
}
1127
1173
1128
1174
/**
1129
- * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
1175
+ * usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore
1130
1176
* @udc: The UDC to be stopped
1131
1177
*
1132
1178
* This call is issued by the UDC Class driver after calling
@@ -1135,8 +1181,11 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
1135
1181
* The details are implementation specific, but it can go as
1136
1182
* far as powering off UDC completely and disable its data
1137
1183
* line pullups.
1184
+ *
1185
+ * Caller should acquire connect lock before invoking this function.
1138
1186
*/
1139
- static inline void usb_gadget_udc_stop (struct usb_udc * udc )
1187
+ static inline void usb_gadget_udc_stop_locked (struct usb_udc * udc )
1188
+ __must_hold (& udc - > connect_lock )
1140
1189
{
1141
1190
if (!udc -> started ) {
1142
1191
dev_err (& udc -> dev , "UDC had already stopped\n" );
@@ -1295,6 +1344,7 @@ int usb_add_gadget(struct usb_gadget *gadget)
1295
1344
1296
1345
udc -> gadget = gadget ;
1297
1346
gadget -> udc = udc ;
1347
+ mutex_init (& udc -> connect_lock );
1298
1348
1299
1349
udc -> started = false;
1300
1350
@@ -1496,11 +1546,15 @@ static int gadget_bind_driver(struct device *dev)
1496
1546
if (ret )
1497
1547
goto err_bind ;
1498
1548
1499
- ret = usb_gadget_udc_start (udc );
1500
- if (ret )
1549
+ mutex_lock (& udc -> connect_lock );
1550
+ ret = usb_gadget_udc_start_locked (udc );
1551
+ if (ret ) {
1552
+ mutex_unlock (& udc -> connect_lock );
1501
1553
goto err_start ;
1554
+ }
1502
1555
usb_gadget_enable_async_callbacks (udc );
1503
- usb_udc_connect_control (udc );
1556
+ usb_udc_connect_control_locked (udc );
1557
+ mutex_unlock (& udc -> connect_lock );
1504
1558
1505
1559
kobject_uevent (& udc -> dev .kobj , KOBJ_CHANGE );
1506
1560
return 0 ;
@@ -1531,12 +1585,14 @@ static void gadget_unbind_driver(struct device *dev)
1531
1585
1532
1586
kobject_uevent (& udc -> dev .kobj , KOBJ_CHANGE );
1533
1587
1534
- usb_gadget_disconnect (gadget );
1588
+ mutex_lock (& udc -> connect_lock );
1589
+ usb_gadget_disconnect_locked (gadget );
1535
1590
usb_gadget_disable_async_callbacks (udc );
1536
1591
if (gadget -> irq )
1537
1592
synchronize_irq (gadget -> irq );
1538
1593
udc -> driver -> unbind (gadget );
1539
- usb_gadget_udc_stop (udc );
1594
+ usb_gadget_udc_stop_locked (udc );
1595
+ mutex_unlock (& udc -> connect_lock );
1540
1596
1541
1597
mutex_lock (& udc_lock );
1542
1598
driver -> is_bound = false;
@@ -1622,11 +1678,15 @@ static ssize_t soft_connect_store(struct device *dev,
1622
1678
}
1623
1679
1624
1680
if (sysfs_streq (buf , "connect" )) {
1625
- usb_gadget_udc_start (udc );
1626
- usb_gadget_connect (udc -> gadget );
1681
+ mutex_lock (& udc -> connect_lock );
1682
+ usb_gadget_udc_start_locked (udc );
1683
+ usb_gadget_connect_locked (udc -> gadget );
1684
+ mutex_unlock (& udc -> connect_lock );
1627
1685
} else if (sysfs_streq (buf , "disconnect" )) {
1628
- usb_gadget_disconnect (udc -> gadget );
1629
- usb_gadget_udc_stop (udc );
1686
+ mutex_lock (& udc -> connect_lock );
1687
+ usb_gadget_disconnect_locked (udc -> gadget );
1688
+ usb_gadget_udc_stop_locked (udc );
1689
+ mutex_unlock (& udc -> connect_lock );
1630
1690
} else {
1631
1691
dev_err (dev , "unsupported command '%s'\n" , buf );
1632
1692
ret = - EINVAL ;
0 commit comments