Skip to content

Commit 046050f

Browse files
committed
extcon: Update the prototype of extcon_register_notifier() with enum extcon
Previously, extcon consumer driver used the extcon_register_interest() to register the notifier chain and then to receive the notifier event when external connector's state is changed. When registering the notifier chain for specific external connector with extcon_register_interest(), it used the the string name of external connector directly. There are potential problem because of unclear, non-standard and inconsequent cable name. Namely, it is not appropriate method to identify each external connector. So, this patch modify the prototype of extcon_register_notifier() by using the 'enum extcon' which are the unique id for each external connector instead of unclear string method. - Previously, the extcon consumer driver used the extcon_register_interest() with 'cable_name' to point out the specific external connector. Also. it used the un-needed structure (struct extcon_specific_cable_nb). : int extcon_register_interest(struct extcon_specific_cable_nb *obj, const char *extcon_name, const char *cable_name, struct notifier_block *nb) - Newly, the updated extcon_register_notifier() would definitely support the same feature to detech the changed state of external connector without any specific structure (struct extcon_specific_cable_nb). : int extcon_register_notifier(struct extcon_dev *edev, enum extcon id, struct notifier_block *nb) This patch support the both extcon_register_interest() and new extcon_register_ notifier(). But the extcon_{register|unregister}_interest() will be deprecated because extcon core would support the notifier event for extcon consumer driver with only updated extcon_register_notifier() and 'extcon_specific_cable_nb' will be removed if there are no extcon consumer driver with legacy extcon_{register|unregister}_interest(). Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
1 parent 8e9bc36 commit 046050f

File tree

2 files changed

+56
-52
lines changed

2 files changed

+56
-52
lines changed

drivers/extcon/extcon.c

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
146146
return find_cable_index_by_id(edev, id);
147147
}
148148

149+
static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached)
150+
{
151+
if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) {
152+
*attached = new ? true : false;
153+
return true;
154+
}
155+
156+
return false;
157+
}
158+
149159
static ssize_t state_show(struct device *dev, struct device_attribute *attr,
150160
char *buf)
151161
{
@@ -254,23 +264,27 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
254264
char *envp[3];
255265
int env_offset = 0;
256266
int length;
267+
int index;
257268
unsigned long flags;
269+
bool attached;
258270

259271
spin_lock_irqsave(&edev->lock, flags);
260272

261273
if (edev->state != ((edev->state & ~mask) | (state & mask))) {
262-
u32 old_state = edev->state;
263-
264274
if (check_mutually_exclusive(edev, (edev->state & ~mask) |
265275
(state & mask))) {
266276
spin_unlock_irqrestore(&edev->lock, flags);
267277
return -EPERM;
268278
}
269279

280+
for (index = 0; index < edev->max_supported; index++) {
281+
if (is_extcon_changed(edev->state, state, index, &attached))
282+
raw_notifier_call_chain(&edev->nh[index], attached, edev);
283+
}
284+
270285
edev->state &= ~mask;
271286
edev->state |= state & mask;
272287

273-
raw_notifier_call_chain(&edev->nh, old_state, edev);
274288
/* This could be in interrupt handler */
275289
prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
276290
if (prop_buf) {
@@ -423,29 +437,6 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
423437
}
424438
EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
425439

426-
static int _call_per_cable(struct notifier_block *nb, unsigned long val,
427-
void *ptr)
428-
{
429-
struct extcon_specific_cable_nb *obj = container_of(nb,
430-
struct extcon_specific_cable_nb, internal_nb);
431-
struct extcon_dev *edev = ptr;
432-
433-
if ((val & (1 << obj->cable_index)) !=
434-
(edev->state & (1 << obj->cable_index))) {
435-
bool cable_state = true;
436-
437-
obj->previous_value = val;
438-
439-
if (val & (1 << obj->cable_index))
440-
cable_state = false;
441-
442-
return obj->user_nb->notifier_call(obj->user_nb,
443-
cable_state, ptr);
444-
}
445-
446-
return NOTIFY_OK;
447-
}
448-
449440
/**
450441
* extcon_register_interest() - Register a notifier for a state change of a
451442
* specific cable, not an entier set of cables of a
@@ -491,11 +482,10 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
491482

492483
obj->user_nb = nb;
493484

494-
obj->internal_nb.notifier_call = _call_per_cable;
495-
496485
spin_lock_irqsave(&obj->edev->lock, flags);
497-
ret = raw_notifier_chain_register(&obj->edev->nh,
498-
&obj->internal_nb);
486+
ret = raw_notifier_chain_register(
487+
&obj->edev->nh[obj->cable_index],
488+
obj->user_nb);
499489
spin_unlock_irqrestore(&obj->edev->lock, flags);
500490
} else {
501491
struct class_dev_iter iter;
@@ -538,7 +528,8 @@ int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
538528
return -EINVAL;
539529

540530
spin_lock_irqsave(&obj->edev->lock, flags);
541-
ret = raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
531+
ret = raw_notifier_chain_unregister(
532+
&obj->edev->nh[obj->cable_index], obj->user_nb);
542533
spin_unlock_irqrestore(&obj->edev->lock, flags);
543534

544535
return ret;
@@ -548,21 +539,24 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest);
548539
/**
549540
* extcon_register_notifier() - Register a notifiee to get notified by
550541
* any attach status changes from the extcon.
551-
* @edev: the extcon device.
542+
* @edev: the extcon device that has the external connecotr.
543+
* @id: the unique id of each external connector in extcon enumeration.
552544
* @nb: a notifier block to be registered.
553545
*
554546
* Note that the second parameter given to the callback of nb (val) is
555547
* "old_state", not the current state. The current state can be retrieved
556548
* by looking at the third pameter (edev pointer)'s state value.
557549
*/
558-
int extcon_register_notifier(struct extcon_dev *edev,
559-
struct notifier_block *nb)
550+
int extcon_register_notifier(struct extcon_dev *edev, enum extcon id,
551+
struct notifier_block *nb)
560552
{
561553
unsigned long flags;
562-
int ret;
554+
int ret, idx;
555+
556+
idx = find_cable_index_by_id(edev, id);
563557

564558
spin_lock_irqsave(&edev->lock, flags);
565-
ret = raw_notifier_chain_register(&edev->nh, nb);
559+
ret = raw_notifier_chain_register(&edev->nh[idx], nb);
566560
spin_unlock_irqrestore(&edev->lock, flags);
567561

568562
return ret;
@@ -571,17 +565,20 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier);
571565

572566
/**
573567
* extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
574-
* @edev: the extcon device.
575-
* @nb: a registered notifier block to be unregistered.
568+
* @edev: the extcon device that has the external connecotr.
569+
* @id: the unique id of each external connector in extcon enumeration.
570+
* @nb: a notifier block to be registered.
576571
*/
577-
int extcon_unregister_notifier(struct extcon_dev *edev,
578-
struct notifier_block *nb)
572+
int extcon_unregister_notifier(struct extcon_dev *edev, enum extcon id,
573+
struct notifier_block *nb)
579574
{
580575
unsigned long flags;
581-
int ret;
576+
int ret, idx;
577+
578+
idx = find_cable_index_by_id(edev, id);
582579

583580
spin_lock_irqsave(&edev->lock, flags);
584-
ret = raw_notifier_chain_unregister(&edev->nh, nb);
581+
ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
585582
spin_unlock_irqrestore(&edev->lock, flags);
586583

587584
return ret;
@@ -893,7 +890,15 @@ int extcon_dev_register(struct extcon_dev *edev)
893890

894891
spin_lock_init(&edev->lock);
895892

896-
RAW_INIT_NOTIFIER_HEAD(&edev->nh);
893+
edev->nh = devm_kzalloc(&edev->dev,
894+
sizeof(*edev->nh) * edev->max_supported, GFP_KERNEL);
895+
if (!edev->nh) {
896+
ret = -ENOMEM;
897+
goto err_dev;
898+
}
899+
900+
for (index = 0; index < edev->max_supported; index++)
901+
RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
897902

898903
dev_set_drvdata(&edev->dev, edev);
899904
edev->state = 0;

include/linux/extcon.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ struct extcon_dev {
116116

117117
/* Internal data. Please do not set. */
118118
struct device dev;
119-
struct raw_notifier_head nh;
119+
struct raw_notifier_head *nh;
120120
struct list_head entry;
121121
int max_supported;
122122
spinlock_t lock; /* could be called by irq handler */
@@ -155,16 +155,13 @@ struct extcon_cable {
155155
/**
156156
* struct extcon_specific_cable_nb - An internal data for
157157
* extcon_register_interest().
158-
* @internal_nb: A notifier block bridging extcon notifier
159-
* and cable notifier.
160158
* @user_nb: user provided notifier block for events from
161159
* a specific cable.
162160
* @cable_index: the target cable.
163161
* @edev: the target extcon device.
164162
* @previous_value: the saved previous event value.
165163
*/
166164
struct extcon_specific_cable_nb {
167-
struct notifier_block internal_nb;
168165
struct notifier_block *user_nb;
169166
int cable_index;
170167
struct extcon_dev *edev;
@@ -240,10 +237,10 @@ extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb);
240237
* we do not recommend to use this for normal 'notifiee' device drivers who
241238
* want to be notified by a specific external port of the notifier.
242239
*/
243-
extern int extcon_register_notifier(struct extcon_dev *edev,
240+
extern int extcon_register_notifier(struct extcon_dev *edev, enum extcon id,
241+
struct notifier_block *nb);
242+
extern int extcon_unregister_notifier(struct extcon_dev *edev, enum extcon id,
244243
struct notifier_block *nb);
245-
extern int extcon_unregister_notifier(struct extcon_dev *edev,
246-
struct notifier_block *nb);
247244

248245
/*
249246
* Following API get the extcon device from devicetree.
@@ -333,13 +330,15 @@ static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
333330
}
334331

335332
static inline int extcon_register_notifier(struct extcon_dev *edev,
336-
struct notifier_block *nb)
333+
enum extcon id,
334+
struct notifier_block *nb)
337335
{
338336
return 0;
339337
}
340338

341339
static inline int extcon_unregister_notifier(struct extcon_dev *edev,
342-
struct notifier_block *nb)
340+
enum extcon id,
341+
struct notifier_block *nb)
343342
{
344343
return 0;
345344
}

0 commit comments

Comments
 (0)