@@ -66,20 +66,21 @@ struct dock_station {
66
66
spinlock_t dd_lock ;
67
67
struct mutex hp_lock ;
68
68
struct list_head dependent_devices ;
69
- struct list_head hotplug_devices ;
70
69
71
70
struct list_head sibling ;
72
71
struct platform_device * dock_device ;
73
72
};
74
73
static LIST_HEAD (dock_stations );
75
74
static int dock_station_count ;
75
+ static DEFINE_MUTEX (hotplug_lock );
76
76
77
77
struct dock_dependent_device {
78
78
struct list_head list ;
79
- struct list_head hotplug_list ;
80
79
acpi_handle handle ;
81
- const struct acpi_dock_ops * ops ;
82
- void * context ;
80
+ const struct acpi_dock_ops * hp_ops ;
81
+ void * hp_context ;
82
+ unsigned int hp_refcount ;
83
+ void (* hp_release )(void * );
83
84
};
84
85
85
86
#define DOCK_DOCKING 0x00000001
@@ -111,7 +112,6 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
111
112
112
113
dd -> handle = handle ;
113
114
INIT_LIST_HEAD (& dd -> list );
114
- INIT_LIST_HEAD (& dd -> hotplug_list );
115
115
116
116
spin_lock (& ds -> dd_lock );
117
117
list_add_tail (& dd -> list , & ds -> dependent_devices );
@@ -121,35 +121,90 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
121
121
}
122
122
123
123
/**
124
- * dock_add_hotplug_device - associate a hotplug handler with the dock station
125
- * @ds: The dock station
126
- * @dd: The dependent device struct
127
- *
128
- * Add the dependent device to the dock's hotplug device list
124
+ * dock_init_hotplug - Initialize a hotplug device on a docking station.
125
+ * @dd: Dock-dependent device.
126
+ * @ops: Dock operations to attach to the dependent device.
127
+ * @context: Data to pass to the @ops callbacks and @release.
128
+ * @init: Optional initialization routine to run after setting up context.
129
+ * @release: Optional release routine to run on removal.
129
130
*/
130
- static void
131
- dock_add_hotplug_device ( struct dock_station * ds ,
132
- struct dock_dependent_device * dd )
131
+ static int dock_init_hotplug ( struct dock_dependent_device * dd ,
132
+ const struct acpi_dock_ops * ops , void * context ,
133
+ void ( * init )( void * ), void ( * release )( void * ) )
133
134
{
134
- mutex_lock (& ds -> hp_lock );
135
- list_add_tail (& dd -> hotplug_list , & ds -> hotplug_devices );
136
- mutex_unlock (& ds -> hp_lock );
135
+ int ret = 0 ;
136
+
137
+ mutex_lock (& hotplug_lock );
138
+
139
+ if (dd -> hp_context ) {
140
+ ret = - EEXIST ;
141
+ } else {
142
+ dd -> hp_refcount = 1 ;
143
+ dd -> hp_ops = ops ;
144
+ dd -> hp_context = context ;
145
+ dd -> hp_release = release ;
146
+ }
147
+
148
+ if (!WARN_ON (ret ) && init )
149
+ init (context );
150
+
151
+ mutex_unlock (& hotplug_lock );
152
+ return ret ;
137
153
}
138
154
139
155
/**
140
- * dock_del_hotplug_device - remove a hotplug handler from the dock station
141
- * @ds: The dock station
142
- * @dd: the dependent device struct
156
+ * dock_release_hotplug - Decrement hotplug reference counter of dock device.
157
+ * @dd: Dock-dependent device.
143
158
*
144
- * Delete the dependent device from the dock's hotplug device list
159
+ * Decrement the reference counter of @dd and if 0, detach its hotplug
160
+ * operations from it, reset its context pointer and run the optional release
161
+ * routine if present.
145
162
*/
146
- static void
147
- dock_del_hotplug_device (struct dock_station * ds ,
148
- struct dock_dependent_device * dd )
163
+ static void dock_release_hotplug (struct dock_dependent_device * dd )
149
164
{
150
- mutex_lock (& ds -> hp_lock );
151
- list_del (& dd -> hotplug_list );
152
- mutex_unlock (& ds -> hp_lock );
165
+ void (* release )(void * ) = NULL ;
166
+ void * context = NULL ;
167
+
168
+ mutex_lock (& hotplug_lock );
169
+
170
+ if (dd -> hp_context && !-- dd -> hp_refcount ) {
171
+ dd -> hp_ops = NULL ;
172
+ context = dd -> hp_context ;
173
+ dd -> hp_context = NULL ;
174
+ release = dd -> hp_release ;
175
+ dd -> hp_release = NULL ;
176
+ }
177
+
178
+ if (release && context )
179
+ release (context );
180
+
181
+ mutex_unlock (& hotplug_lock );
182
+ }
183
+
184
+ static void dock_hotplug_event (struct dock_dependent_device * dd , u32 event ,
185
+ bool uevent )
186
+ {
187
+ acpi_notify_handler cb = NULL ;
188
+ bool run = false;
189
+
190
+ mutex_lock (& hotplug_lock );
191
+
192
+ if (dd -> hp_context ) {
193
+ run = true;
194
+ dd -> hp_refcount ++ ;
195
+ if (dd -> hp_ops )
196
+ cb = uevent ? dd -> hp_ops -> uevent : dd -> hp_ops -> handler ;
197
+ }
198
+
199
+ mutex_unlock (& hotplug_lock );
200
+
201
+ if (!run )
202
+ return ;
203
+
204
+ if (cb )
205
+ cb (dd -> handle , event , dd -> hp_context );
206
+
207
+ dock_release_hotplug (dd );
153
208
}
154
209
155
210
/**
@@ -360,9 +415,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
360
415
/*
361
416
* First call driver specific hotplug functions
362
417
*/
363
- list_for_each_entry (dd , & ds -> hotplug_devices , hotplug_list )
364
- if (dd -> ops && dd -> ops -> handler )
365
- dd -> ops -> handler (dd -> handle , event , dd -> context );
418
+ list_for_each_entry (dd , & ds -> dependent_devices , list )
419
+ dock_hotplug_event (dd , event , false);
366
420
367
421
/*
368
422
* Now make sure that an acpi_device is created for each
@@ -398,9 +452,8 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
398
452
if (num == DOCK_EVENT )
399
453
kobject_uevent_env (& dev -> kobj , KOBJ_CHANGE , envp );
400
454
401
- list_for_each_entry (dd , & ds -> hotplug_devices , hotplug_list )
402
- if (dd -> ops && dd -> ops -> uevent )
403
- dd -> ops -> uevent (dd -> handle , event , dd -> context );
455
+ list_for_each_entry (dd , & ds -> dependent_devices , list )
456
+ dock_hotplug_event (dd , event , true);
404
457
405
458
if (num != DOCK_EVENT )
406
459
kobject_uevent_env (& dev -> kobj , KOBJ_CHANGE , envp );
@@ -570,19 +623,24 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
570
623
* @handle: the handle of the device
571
624
* @ops: handlers to call after docking
572
625
* @context: device specific data
626
+ * @init: Optional initialization routine to run after registration
627
+ * @release: Optional release routine to run on unregistration
573
628
*
574
629
* If a driver would like to perform a hotplug operation after a dock
575
630
* event, they can register an acpi_notifiy_handler to be called by
576
631
* the dock driver after _DCK is executed.
577
632
*/
578
- int
579
- register_hotplug_dock_device ( acpi_handle handle , const struct acpi_dock_ops * ops ,
580
- void * context )
633
+ int register_hotplug_dock_device ( acpi_handle handle ,
634
+ const struct acpi_dock_ops * ops , void * context ,
635
+ void ( * init )( void * ), void ( * release )( void * ) )
581
636
{
582
637
struct dock_dependent_device * dd ;
583
638
struct dock_station * dock_station ;
584
639
int ret = - EINVAL ;
585
640
641
+ if (WARN_ON (!context ))
642
+ return - EINVAL ;
643
+
586
644
if (!dock_station_count )
587
645
return - ENODEV ;
588
646
@@ -597,12 +655,8 @@ register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops
597
655
* ops
598
656
*/
599
657
dd = find_dock_dependent_device (dock_station , handle );
600
- if (dd ) {
601
- dd -> ops = ops ;
602
- dd -> context = context ;
603
- dock_add_hotplug_device (dock_station , dd );
658
+ if (dd && !dock_init_hotplug (dd , ops , context , init , release ))
604
659
ret = 0 ;
605
- }
606
660
}
607
661
608
662
return ret ;
@@ -624,7 +678,7 @@ void unregister_hotplug_dock_device(acpi_handle handle)
624
678
list_for_each_entry (dock_station , & dock_stations , sibling ) {
625
679
dd = find_dock_dependent_device (dock_station , handle );
626
680
if (dd )
627
- dock_del_hotplug_device ( dock_station , dd );
681
+ dock_release_hotplug ( dd );
628
682
}
629
683
}
630
684
EXPORT_SYMBOL_GPL (unregister_hotplug_dock_device );
@@ -953,7 +1007,6 @@ static int __init dock_add(acpi_handle handle)
953
1007
mutex_init (& dock_station -> hp_lock );
954
1008
spin_lock_init (& dock_station -> dd_lock );
955
1009
INIT_LIST_HEAD (& dock_station -> sibling );
956
- INIT_LIST_HEAD (& dock_station -> hotplug_devices );
957
1010
ATOMIC_INIT_NOTIFIER_HEAD (& dock_notifier_list );
958
1011
INIT_LIST_HEAD (& dock_station -> dependent_devices );
959
1012
@@ -993,30 +1046,6 @@ static int __init dock_add(acpi_handle handle)
993
1046
return ret ;
994
1047
}
995
1048
996
- /**
997
- * dock_remove - free up resources related to the dock station
998
- */
999
- static int dock_remove (struct dock_station * ds )
1000
- {
1001
- struct dock_dependent_device * dd , * tmp ;
1002
- struct platform_device * dock_device = ds -> dock_device ;
1003
-
1004
- if (!dock_station_count )
1005
- return 0 ;
1006
-
1007
- /* remove dependent devices */
1008
- list_for_each_entry_safe (dd , tmp , & ds -> dependent_devices , list )
1009
- kfree (dd );
1010
-
1011
- list_del (& ds -> sibling );
1012
-
1013
- /* cleanup sysfs */
1014
- sysfs_remove_group (& dock_device -> dev .kobj , & dock_attribute_group );
1015
- platform_device_unregister (dock_device );
1016
-
1017
- return 0 ;
1018
- }
1019
-
1020
1049
/**
1021
1050
* find_dock_and_bay - look for dock stations and bays
1022
1051
* @handle: acpi handle of a device
@@ -1035,7 +1064,7 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
1035
1064
return AE_OK ;
1036
1065
}
1037
1066
1038
- static int __init dock_init (void )
1067
+ int __init acpi_dock_init (void )
1039
1068
{
1040
1069
if (acpi_disabled )
1041
1070
return 0 ;
@@ -1054,19 +1083,3 @@ static int __init dock_init(void)
1054
1083
ACPI_DOCK_DRIVER_DESCRIPTION , dock_station_count );
1055
1084
return 0 ;
1056
1085
}
1057
-
1058
- static void __exit dock_exit (void )
1059
- {
1060
- struct dock_station * tmp , * dock_station ;
1061
-
1062
- unregister_acpi_bus_notifier (& dock_acpi_notifier );
1063
- list_for_each_entry_safe (dock_station , tmp , & dock_stations , sibling )
1064
- dock_remove (dock_station );
1065
- }
1066
-
1067
- /*
1068
- * Must be called before drivers of devices in dock, otherwise we can't know
1069
- * which devices are in a dock
1070
- */
1071
- subsys_initcall (dock_init );
1072
- module_exit (dock_exit );
0 commit comments