From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755024AbbEOObg (ORCPT ); Fri, 15 May 2015 10:31:36 -0400 Received: from mailout4.samsung.com ([203.254.224.34]:50508 "EHLO mailout4.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754254AbbEOObW (ORCPT ); Fri, 15 May 2015 10:31:22 -0400 X-AuditID: cbfee68d-f79106d00000728c-14-55560337434b From: Chanwoo Choi To: linux-kernel@vger.kernel.org Cc: myungjoo.ham@samsung.com, cw00.choi@samsung.com, k.kozlowski@samsung.com, ckeepax@opensource.wolfsonmicro.com, gg@slimlogic.co.uk, kishon@ti.com, jaewon02.kim@samsung.com, rogerq@ti.com, ramakrishna.pallala@intel.com, george.cherian@ti.com, balbi@ti.com, aaro.koskinen@iki.fi Subject: [PATCH 2/2] extcon: Update the prototype of extcon_register_notifier() with enum extcon Date: Fri, 15 May 2015 23:31:18 +0900 Message-id: <1431700278-30465-3-git-send-email-cw00.choi@samsung.com> X-Mailer: git-send-email 1.8.5.5 In-reply-to: <1431700278-30465-1-git-send-email-cw00.choi@samsung.com> References: <1431700278-30465-1-git-send-email-cw00.choi@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrDLMWRmVeSWpSXmKPExsWyRsSkSNecOSzUYO5yWYs1LxwsDt6vt/g3 5Qa7xfUvz1ktTh1czmrRv8XFYkfDEVaL1y8MLS487WGzuLxrDpvF7cYVbBYL39xksuh5pOXA 63H460IWj8V7XjJ5vJz4m82jb8sqRo+pU/4yehy/sZ3J4/MmuQD2KC6blNSczLLUIn27BK6M a5//sRasD6yY8OsHUwPjYqcuRk4OCQETiWcdF9khbDGJC/fWs4HYQgJLGSVaL9jC1Oz71sja xcgFFJ/OKHHrbyMTRNEXRollPx1BbDYBLYn9L26ANYsIKEhs7n0G1sAsMJdJYs6kPawgCWGB JInf15pZuhg5OFgEVCW2zqsFCfMKuEr8ut/LCLFMQWLZ8plg5ZwCbhKX9txkBikXAqo5vEAG ZKSEwCV2ib2z/rKA1LAICEh8m3wIbKSEgKzEpgPMEGMkJQ6uuMEygVF4ASPDKkbR1ILkguKk 9CJDveLE3OLSvHS95PzcTYzASDn971nvDsbbB6wPMQpwMCrx8CY4hIYKsSaWFVfmHmI0Bdow kVlKNDkfGI95JfGGxmZGFqYmpsZG5pZmSuK8ilI/g4UE0hNLUrNTUwtSi+KLSnNSiw8xMnFw SjUwdp7jbBMxPX3pylnP7kj520viz7ycKH9d75Dg1szWS+v2aa8RVDuR/Sj1p639/XVb7tpd +bV0v3GyloXY42Nr9sfxHdpru0qkr7RU79n/ktSfFn7cT+dN7L/cpCIwM99x55FdWnGGNaoJ gpFW3xjq7Fh1Z5/rPPIq1ExXaf80x7Xvs9qkxMU/KLEUZyQaajEXFScCAMl5IWuPAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrOIsWRmVeSWpSXmKPExsVy+t9jQV1z5rBQg0l/RS3WvHCwOHi/3uLf lBvsFte/PGe1OHVwOatF/xYXix0NR1gtXr8wtLjwtIfN4vKuOWwWtxtXsFksfHOTyaLnkZYD r8fhrwtZPBbvecnk8XLibzaPvi2rGD2mTvnL6HH8xnYmj8+b5ALYoxoYbTJSE1NSixRS85Lz UzLz0m2VvIPjneNNzQwMdQ0tLcyVFPISc1NtlVx8AnTdMnOATlVSKEvMKQUKBSQWFyvp22Ga EBripmsB0xih6xsSBNdjZIAGEtYwZlz7/I+1YH1gxYRfP5gaGBc7dTFyckgImEjs+9bICmGL SVy4t56ti5GLQ0hgOqPErb+NTCAJIYEvjBLLfjqC2GwCWhL7X9xgA7FFBBQkNvc+YwVpYBaY yyQxZ9IesEnCAkkSv681s3QxcnCwCKhKbJ1XCxLmFXCV+HW/lxFimYLEsuUzwco5BdwkLu25 yQxSLgRUc3iBzARG3gWMDKsYRVMLkguKk9JzDfWKE3OLS/PS9ZLzczcxgiPxmdQOxpUNFocY BTgYlXh4Ex1CQ4VYE8uKK3MPMUpwMCuJ8NYwhIUK8aYkVlalFuXHF5XmpBYfYjQFumkis5Ro cj4wSeSVxBsam5gZWRqZG1oYGZsrifOezPcJFRJITyxJzU5NLUgtgulj4uCUamD0fy/9WPqw JOvRBXFfJns7lR7Vi6ibeX72rK/7t20JTFwcVhyY/6S7t3brEb679/s1rdZ+3MebI64/M/Du dKc1OSGvnbwrFjZ8aJ/yb1Ehz4ZdPf2HdjkW9B15u7yX6dpbMbPPCdOuTdyyKvv7s7ky1yac Mpqa33Aj6M+a65mz31yX2ufTtaywSomlOCPRUIu5qDgRAIuXLLvaAgAA DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 Cc: MyungJoo Ham Cc: George Cherian Cc: Felipe Balbi Cc: Aaro Koskinen --- drivers/extcon/extcon.c | 91 ++++++++++++++++++++++++++----------------------- include/linux/extcon.h | 17 +++++---- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 4aeb585..14c8c95 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -111,6 +111,16 @@ static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) return 0; } +static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) +{ + if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { + *attached = new ? true : false; + return true; + } + + return false; +} + static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -219,23 +229,27 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) char *envp[3]; int env_offset = 0; int length; + int index; unsigned long flags; + bool attached; spin_lock_irqsave(&edev->lock, flags); if (edev->state != ((edev->state & ~mask) | (state & mask))) { - u32 old_state = edev->state; - if (check_mutually_exclusive(edev, (edev->state & ~mask) | (state & mask))) { spin_unlock_irqrestore(&edev->lock, flags); return -EPERM; } + for (index = 0; index < edev->max_supported; index++) { + if (is_extcon_changed(edev->state, state, index, &attached)) + raw_notifier_call_chain(&edev->nh[index], attached, edev); + } + edev->state &= ~mask; edev->state |= state & mask; - raw_notifier_call_chain(&edev->nh, old_state, edev); /* This could be in interrupt handler */ prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); if (prop_buf) { @@ -433,29 +447,6 @@ out: } EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); -static int _call_per_cable(struct notifier_block *nb, unsigned long val, - void *ptr) -{ - struct extcon_specific_cable_nb *obj = container_of(nb, - struct extcon_specific_cable_nb, internal_nb); - struct extcon_dev *edev = ptr; - - if ((val & (1 << obj->cable_index)) != - (edev->state & (1 << obj->cable_index))) { - bool cable_state = true; - - obj->previous_value = val; - - if (val & (1 << obj->cable_index)) - cable_state = false; - - return obj->user_nb->notifier_call(obj->user_nb, - cable_state, ptr); - } - - return NOTIFY_OK; -} - /** * extcon_register_interest() - Register a notifier for a state change of a * specific cable, not an entier set of cables of a @@ -501,11 +492,10 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, obj->user_nb = nb; - obj->internal_nb.notifier_call = _call_per_cable; - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_register(&obj->edev->nh, - &obj->internal_nb); + ret = raw_notifier_chain_register( + &obj->edev->nh[obj->cable_index], + obj->user_nb); spin_unlock_irqrestore(&obj->edev->lock, flags); } else { struct class_dev_iter iter; @@ -548,7 +538,8 @@ int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) return -EINVAL; spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb); + ret = raw_notifier_chain_unregister( + &obj->edev->nh[obj->cable_index], obj->user_nb); spin_unlock_irqrestore(&obj->edev->lock, flags); return ret; @@ -558,21 +549,24 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest); /** * extcon_register_notifier() - Register a notifiee to get notified by * any attach status changes from the extcon. - * @edev: the extcon device. + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. * @nb: a notifier block to be registered. * * Note that the second parameter given to the callback of nb (val) is * "old_state", not the current state. The current state can be retrieved * by looking at the third pameter (edev pointer)'s state value. */ -int extcon_register_notifier(struct extcon_dev *edev, - struct notifier_block *nb) +int extcon_register_notifier(struct extcon_dev *edev, enum extcon id, + struct notifier_block *nb) { unsigned long flags; - int ret; + int ret, idx; + + idx = extcon_find_cable_index(edev, extcon_name[id]); spin_lock_irqsave(&edev->lock, flags); - ret = raw_notifier_chain_register(&edev->nh, nb); + ret = raw_notifier_chain_register(&edev->nh[idx], nb); spin_unlock_irqrestore(&edev->lock, flags); return ret; @@ -581,17 +575,20 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier); /** * extcon_unregister_notifier() - Unregister a notifiee from the extcon device. - * @edev: the extcon device. - * @nb: a registered notifier block to be unregistered. + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. */ -int extcon_unregister_notifier(struct extcon_dev *edev, - struct notifier_block *nb) +int extcon_unregister_notifier(struct extcon_dev *edev, enum extcon id, + struct notifier_block *nb) { unsigned long flags; - int ret; + int ret, idx; + + idx = extcon_find_cable_index(edev, extcon_name[id]); spin_lock_irqsave(&edev->lock, flags); - ret = raw_notifier_chain_unregister(&edev->nh, nb); + ret = raw_notifier_chain_unregister(&edev->nh[idx], nb); spin_unlock_irqrestore(&edev->lock, flags); return ret; @@ -903,7 +900,15 @@ int extcon_dev_register(struct extcon_dev *edev) spin_lock_init(&edev->lock); - RAW_INIT_NOTIFIER_HEAD(&edev->nh); + edev->nh = devm_kzalloc(&edev->dev, + sizeof(*edev->nh) * edev->max_supported, GFP_KERNEL); + if (!edev->nh) { + ret = -ENOMEM; + goto err_dev; + } + + for (index = 0; index < edev->max_supported; index++) + RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]); dev_set_drvdata(&edev->dev, edev); edev->state = 0; diff --git a/include/linux/extcon.h b/include/linux/extcon.h index de158a1..918ba89 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -135,7 +135,7 @@ struct extcon_dev { /* Internal data. Please do not set. */ struct device dev; - struct raw_notifier_head nh; + struct raw_notifier_head *nh; struct list_head entry; int max_supported; spinlock_t lock; /* could be called by irq handler */ @@ -174,8 +174,6 @@ struct extcon_cable { /** * struct extcon_specific_cable_nb - An internal data for * extcon_register_interest(). - * @internal_nb: A notifier block bridging extcon notifier - * and cable notifier. * @user_nb: user provided notifier block for events from * a specific cable. * @cable_index: the target cable. @@ -183,7 +181,6 @@ struct extcon_cable { * @previous_value: the saved previous event value. */ struct extcon_specific_cable_nb { - struct notifier_block internal_nb; struct notifier_block *user_nb; int cable_index; struct extcon_dev *edev; @@ -259,10 +256,10 @@ extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb); * we do not recommend to use this for normal 'notifiee' device drivers who * want to be notified by a specific external port of the notifier. */ -extern int extcon_register_notifier(struct extcon_dev *edev, +extern int extcon_register_notifier(struct extcon_dev *edev, enum extcon id, + struct notifier_block *nb); +extern int extcon_unregister_notifier(struct extcon_dev *edev, enum extcon id, struct notifier_block *nb); -extern int extcon_unregister_notifier(struct extcon_dev *edev, - struct notifier_block *nb); /* * Following API get the extcon device from devicetree. @@ -352,13 +349,15 @@ static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) } static inline int extcon_register_notifier(struct extcon_dev *edev, - struct notifier_block *nb) + enum extcon id, + struct notifier_block *nb) { return 0; } static inline int extcon_unregister_notifier(struct extcon_dev *edev, - struct notifier_block *nb) + enum extcon id, + struct notifier_block *nb) { return 0; } -- 1.8.5.5