Skip to content

Commit 815429b

Browse files
committed
extcon: Add new extcon_register_notifier_all() to monitor all external connectors
The extcon core already provides the extcon_register_notifier() function in order to register the notifier block which is used to monitor the state change for the specific external connector such as EXTCON_USB, EXTCON_USB_HOST and so on. The extcon consumer uses the this function. The extcon consumer might need to monitor the all supported external connectors from the extcon device. In this case, The extcon consumer should have each notifier_block structure for each external connector. This patch adds the new extcon_register_notifier_all() function that extcon consumer is able to monitor the state change of all supported external connectors by using only one notifier_block structure. - List of new added functions: int extcon_register_notifier_all(struct extcon_dev *edev, struct notifier_block *nb); int extcon_unregister_notifier_all(struct extcon_dev *edev, struct notifier_block *nb); int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev, struct notifier_block *nb); void devm_extcon_unregister_notifier_all(struct device *dev, struct extcon_dev *edev, struct notifier_block *nb); Suggested-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Tested-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Hans de Goede <hdegoede@redhat.com>
1 parent c02ed2e commit 815429b

File tree

4 files changed

+146
-5
lines changed

4 files changed

+146
-5
lines changed

drivers/extcon/devres.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
5050
extcon_unregister_notifier(this->edev, this->id, this->nb);
5151
}
5252

53+
static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
54+
{
55+
struct extcon_dev_notifier_devres *this = res;
56+
57+
extcon_unregister_notifier_all(this->edev, this->nb);
58+
}
59+
5360
/**
5461
* devm_extcon_dev_allocate - Allocate managed extcon device
5562
* @dev: device owning the extcon device being created
@@ -214,3 +221,57 @@ void devm_extcon_unregister_notifier(struct device *dev,
214221
devm_extcon_dev_match, edev));
215222
}
216223
EXPORT_SYMBOL(devm_extcon_unregister_notifier);
224+
225+
/**
226+
* devm_extcon_register_notifier_all()
227+
* - Resource-managed extcon_register_notifier_all()
228+
* @dev: device to allocate extcon device
229+
* @edev: the extcon device that has the external connecotr.
230+
* @nb: a notifier block to be registered.
231+
*
232+
* This function manages automatically the notifier of extcon device using
233+
* device resource management and simplify the control of unregistering
234+
* the notifier of extcon device. To get more information, refer that function.
235+
*
236+
* Returns 0 if success or negaive error number if failure.
237+
*/
238+
int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
239+
struct notifier_block *nb)
240+
{
241+
struct extcon_dev_notifier_devres *ptr;
242+
int ret;
243+
244+
ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
245+
GFP_KERNEL);
246+
if (!ptr)
247+
return -ENOMEM;
248+
249+
ret = extcon_register_notifier_all(edev, nb);
250+
if (ret) {
251+
devres_free(ptr);
252+
return ret;
253+
}
254+
255+
ptr->edev = edev;
256+
ptr->nb = nb;
257+
devres_add(dev, ptr);
258+
259+
return 0;
260+
}
261+
EXPORT_SYMBOL(devm_extcon_register_notifier_all);
262+
263+
/**
264+
* devm_extcon_unregister_notifier_all()
265+
* - Resource-managed extcon_unregister_notifier_all()
266+
* @dev: device to allocate extcon device
267+
* @edev: the extcon device that has the external connecotr.
268+
* @nb: a notifier block to be registered.
269+
*/
270+
void devm_extcon_unregister_notifier_all(struct device *dev,
271+
struct extcon_dev *edev,
272+
struct notifier_block *nb)
273+
{
274+
WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
275+
devm_extcon_dev_match, edev));
276+
}
277+
EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);

drivers/extcon/extcon.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,19 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id)
448448
spin_lock_irqsave(&edev->lock, flags);
449449

450450
state = !!(edev->state & BIT(index));
451+
452+
/*
453+
* Call functions in a raw notifier chain for the specific one
454+
* external connector.
455+
*/
451456
raw_notifier_call_chain(&edev->nh[index], state, edev);
452457

458+
/*
459+
* Call functions in a raw notifier chain for the all supported
460+
* external connectors.
461+
*/
462+
raw_notifier_call_chain(&edev->nh_all, state, edev);
463+
453464
/* This could be in interrupt handler */
454465
prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
455466
if (!prop_buf) {
@@ -954,6 +965,59 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
954965
}
955966
EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
956967

968+
/**
969+
* extcon_register_notifier_all() - Register a notifier block for all connectors
970+
* @edev: the extcon device that has the external connecotr.
971+
* @nb: a notifier block to be registered.
972+
*
973+
* This fucntion registers a notifier block in order to receive the state
974+
* change of all supported external connectors from extcon device.
975+
* And The second parameter given to the callback of nb (val) is
976+
* the current state and third parameter is the edev pointer.
977+
*
978+
* Returns 0 if success or error number if fail
979+
*/
980+
int extcon_register_notifier_all(struct extcon_dev *edev,
981+
struct notifier_block *nb)
982+
{
983+
unsigned long flags;
984+
int ret;
985+
986+
if (!edev || !nb)
987+
return -EINVAL;
988+
989+
spin_lock_irqsave(&edev->lock, flags);
990+
ret = raw_notifier_chain_register(&edev->nh_all, nb);
991+
spin_unlock_irqrestore(&edev->lock, flags);
992+
993+
return ret;
994+
}
995+
EXPORT_SYMBOL_GPL(extcon_register_notifier_all);
996+
997+
/**
998+
* extcon_unregister_notifier_all() - Unregister a notifier block from extcon.
999+
* @edev: the extcon device that has the external connecotr.
1000+
* @nb: a notifier block to be registered.
1001+
*
1002+
* Returns 0 if success or error number if fail
1003+
*/
1004+
int extcon_unregister_notifier_all(struct extcon_dev *edev,
1005+
struct notifier_block *nb)
1006+
{
1007+
unsigned long flags;
1008+
int ret;
1009+
1010+
if (!edev || !nb)
1011+
return -EINVAL;
1012+
1013+
spin_lock_irqsave(&edev->lock, flags);
1014+
ret = raw_notifier_chain_unregister(&edev->nh_all, nb);
1015+
spin_unlock_irqrestore(&edev->lock, flags);
1016+
1017+
return ret;
1018+
}
1019+
EXPORT_SYMBOL_GPL(extcon_unregister_notifier_all);
1020+
9571021
static struct attribute *extcon_attrs[] = {
9581022
&dev_attr_state.attr,
9591023
&dev_attr_name.attr,
@@ -1212,6 +1276,8 @@ int extcon_dev_register(struct extcon_dev *edev)
12121276
for (index = 0; index < edev->max_supported; index++)
12131277
RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
12141278

1279+
RAW_INIT_NOTIFIER_HEAD(&edev->nh_all);
1280+
12151281
dev_set_drvdata(&edev->dev, edev);
12161282
edev->state = 0;
12171283

drivers/extcon/extcon.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
* @dev: Device of this extcon.
2222
* @state: Attach/detach state of this extcon. Do not provide at
2323
* register-time.
24+
* @nh_all: Notifier for the state change events for all supported
25+
* external connectors from this extcon.
2426
* @nh: Notifier for the state change events from this extcon
2527
* @entry: To support list of extcon devices so that users can
2628
* search for extcon devices based on the extcon name.
@@ -43,6 +45,7 @@ struct extcon_dev {
4345

4446
/* Internal data. Please do not set. */
4547
struct device dev;
48+
struct raw_notifier_head nh_all;
4649
struct raw_notifier_head *nh;
4750
struct list_head entry;
4851
int max_supported;

include/linux/extcon.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,11 @@ extern int extcon_set_property_capability(struct extcon_dev *edev,
236236
unsigned int id, unsigned int prop);
237237

238238
/*
239-
* Following APIs are to monitor every action of a notifier.
240-
* Registrar gets notified for every external port of a connection device.
241-
* Probably this could be used to debug an action of notifier; however,
242-
* we do not recommend to use this for normal 'notifiee' device drivers who
243-
* want to be notified by a specific external port of the notifier.
239+
* Following APIs are to monitor the status change of the external connectors.
240+
* extcon_register_notifier(*edev, id, *nb) : Register a notifier block
241+
* for specific external connector of the extcon.
242+
* extcon_register_notifier_all(*edev, *nb) : Register a notifier block
243+
* for all supported external connectors of the extcon.
244244
*/
245245
extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
246246
struct notifier_block *nb);
@@ -253,6 +253,17 @@ extern void devm_extcon_unregister_notifier(struct device *dev,
253253
struct extcon_dev *edev, unsigned int id,
254254
struct notifier_block *nb);
255255

256+
extern int extcon_register_notifier_all(struct extcon_dev *edev,
257+
struct notifier_block *nb);
258+
extern int extcon_unregister_notifier_all(struct extcon_dev *edev,
259+
struct notifier_block *nb);
260+
extern int devm_extcon_register_notifier_all(struct device *dev,
261+
struct extcon_dev *edev,
262+
struct notifier_block *nb);
263+
extern void devm_extcon_unregister_notifier_all(struct device *dev,
264+
struct extcon_dev *edev,
265+
struct notifier_block *nb);
266+
256267
/*
257268
* Following API get the extcon device from devicetree.
258269
* This function use phandle of devicetree to get extcon device directly.

0 commit comments

Comments
 (0)