lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 27 Jul 2016 16:41:06 +0900
From:	Chanwoo Choi <cw00.choi@...sung.com>
To:	Chris Zhong <zyw@...k-chips.com>, linux-kernel@...r.kernel.org
Cc:	myungjoo.ham@...sung.com, groeck@...omium.org, cwchoi00@...il.com
Subject: Re: [PATCH 5/6] extcon: Add the synchronization extcon APIs to support
 the notification

Hi Chris,

On 2016년 07월 27일 16:30, Chris Zhong wrote:
> Hi Chanwoo
> 
> On 07/26/2016 08:09 PM, Chanwoo Choi wrote:
>> This patch adds the synchronization extcon APIs to support the notifications
>> for both state and property. When extcon_*_sync() functions is called,
>> the extcon informs the information from extcon provider to extcon client.
>>
>> The extcon driver may need to change the both state and multiple properties
>> at the same time. After setting the data of a external connector,
>> the extcon send the notification to client driver with the extcon_*_sync().
>>
>> The list of new extcon APIs as following:
>> - extcon_sync() : Send the notification for each external connector to
>>         synchronize the information between extcon provider driver
>>         and extcon client driver.
>> - extcon_set_state_sync() : Set the state of external connector with noti.
>> - extcon_set_property_sync() : Set the property of external connector with noti.
>>
>> For example,
>> case 1, change the state of external connector and synchronized the data.
>>     extcon_set_state_sync(edev, EXTCON_USB, 1);
>>
>> case 2, change both the state and property of external connector
>>     and synchronized the data.
>>     extcon_set_state(edev, EXTCON_USB, 1);
>>     extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_ID, 1);
>>     extcon_sync(edev, EXTCON_USB);
>>
>> case 3, change the property of external connector and synchronized the data.
>>     extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0);
>>     extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_ID, 1);
>>     extcon_sync(edev, EXTCON_USB);
>>
>> case 4, change the property of external connector and synchronized the data.
>>     extcon_set_property_sync(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0);
>>
>> Signed-off-by: Chanwoo Choi <cw00.choi@...sung.com>
>> ---
>>   drivers/extcon/extcon.c | 199 ++++++++++++++++++++++++++++++------------------
>>   include/linux/extcon.h  |  30 +++++++-
>>   2 files changed, 152 insertions(+), 77 deletions(-)
>>
>> diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
>> index 73c6981bf559..8572523bfd40 100644
>> --- a/drivers/extcon/extcon.c
>> +++ b/drivers/extcon/extcon.c
>> @@ -280,14 +280,11 @@ static bool is_extcon_attached(struct extcon_dev *edev, unsigned int id,
>>       return ((!!(edev->state & (1 << index))) == 1) ? true : false;
>>   }
>>   -static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached)
>> +static bool is_extcon_changed(struct extcon_dev *edev, int index,
>> +                bool new_state)
>>   {
>> -    if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) {
>> -        *attached = ((new >> idx) & 0x1) ? true : false;
>> -        return true;
>> -    }
>> -
>> -    return false;
>> +    int state = !!(edev->state & (1 << index));
>> +    return (state != new_state) ? true : false;
>>   }
>>     static bool is_extcon_property_supported(unsigned int id, unsigned int prop)
>> @@ -377,21 +374,13 @@ static ssize_t cable_state_show(struct device *dev,
>>   }
>>     /**
>> - * extcon_update_state() - Update the cable attach states of the extcon device
>> - *               only for the masked bits.
>> - * @edev:    the extcon device
>> - * @mask:    the bit mask to designate updated bits.
>> - * @state:    new cable attach status for @edev
>> - *
>> - * Changing the state sends uevent with environment variable containing
>> - * the name of extcon device (envp[0]) and the state output (envp[1]).
>> - * Tizen uses this format for extcon device to get events from ports.
>> - * Android uses this format as well.
>> + * extcon_sync()    - Synchronize the states for both the attached/detached
>> + * @edev:        the extcon device that has the cable.
>>    *
>> - * Note that the notifier provides which bits are changed in the state
>> - * variable with the val parameter (second) to the callback.
>> + * This function send a notification to synchronize the all states of a
>> + * specific external connector
>>    */
>> -static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
>> +int extcon_sync(struct extcon_dev *edev, unsigned int id)
>>   {
>>       char name_buf[120];
>>       char state_buf[120];
>> @@ -400,73 +389,58 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
>>       int env_offset = 0;
>>       int length;
>>       int index;
>> +    int state;
>>       unsigned long flags;
>> -    bool attached;
>>         if (!edev)
>>           return -EINVAL;
>>   -    spin_lock_irqsave(&edev->lock, flags);
>> +    index = find_cable_index_by_id(edev, id);
>> +    if (index < 0)
>> +        return index;
>>   -    if (edev->state != ((edev->state & ~mask) | (state & mask))) {
>> -        u32 old_state;
>> +    state = !!(edev->state & (1 << index));
>> +    raw_notifier_call_chain(&edev->nh[index], state, edev);
>>   -        if (check_mutually_exclusive(edev, (edev->state & ~mask) |
>> -                           (state & mask))) {
>> -            spin_unlock_irqrestore(&edev->lock, flags);
>> -            return -EPERM;
>> -        }
>> +    spin_lock_irqsave(&edev->lock, flags);
>>   -        old_state = edev->state;
>> -        edev->state &= ~mask;
>> -        edev->state |= state & mask;
>> +    /* This could be in interrupt handler */
>> +    prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
>> +    if (!prop_buf) {
>> +        /* Unlock early before uevent */
>> +        spin_unlock_irqrestore(&edev->lock, flags);
>>   -        for (index = 0; index < edev->max_supported; index++) {
>> -            if (is_extcon_changed(old_state, edev->state, index,
>> -                          &attached))
>> -                raw_notifier_call_chain(&edev->nh[index],
>> -                            attached, edev);
>> -        }
>> +        dev_err(&edev->dev, "out of memory in extcon_set_state\n");
>> +        kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
>>   -        /* This could be in interrupt handler */
>> -        prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
>> -        if (prop_buf) {
>> -            length = name_show(&edev->dev, NULL, prop_buf);
>> -            if (length > 0) {
>> -                if (prop_buf[length - 1] == '\n')
>> -                    prop_buf[length - 1] = 0;
>> -                snprintf(name_buf, sizeof(name_buf),
>> -                    "NAME=%s", prop_buf);
>> -                envp[env_offset++] = name_buf;
>> -            }
>> -            length = state_show(&edev->dev, NULL, prop_buf);
>> -            if (length > 0) {
>> -                if (prop_buf[length - 1] == '\n')
>> -                    prop_buf[length - 1] = 0;
>> -                snprintf(state_buf, sizeof(state_buf),
>> -                    "STATE=%s", prop_buf);
>> -                envp[env_offset++] = state_buf;
>> -            }
>> -            envp[env_offset] = NULL;
>> -            /* Unlock early before uevent */
>> -            spin_unlock_irqrestore(&edev->lock, flags);
>> +        return 0;
>> +    }
>>   -            kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
>> -            free_page((unsigned long)prop_buf);
>> -        } else {
>> -            /* Unlock early before uevent */
>> -            spin_unlock_irqrestore(&edev->lock, flags);
>> +    length = name_show(&edev->dev, NULL, prop_buf);
>> +    if (length > 0) {
>> +        if (prop_buf[length - 1] == '\n')
>> +            prop_buf[length - 1] = 0;
>> +        snprintf(name_buf, sizeof(name_buf), "NAME=%s", prop_buf);
>> +        envp[env_offset++] = name_buf;
>> +    }
>>   -            dev_err(&edev->dev, "out of memory in extcon_set_state\n");
>> -            kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
>> -        }
>> -    } else {
>> -        /* No changes */
>> -        spin_unlock_irqrestore(&edev->lock, flags);
>> +    length = state_show(&edev->dev, NULL, prop_buf);
>> +    if (length > 0) {
>> +        if (prop_buf[length - 1] == '\n')
>> +            prop_buf[length - 1] = 0;
>> +        snprintf(state_buf, sizeof(state_buf), "STATE=%s", prop_buf);
>> +        envp[env_offset++] = state_buf;
>>       }
>> +    envp[env_offset] = NULL;
>> +
>> +    /* Unlock early before uevent */
>> +    spin_unlock_irqrestore(&edev->lock, flags);
>> +    kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
>> +    free_page((unsigned long)prop_buf);
>>         return 0;
>>   }
>> +EXPORT_SYMBOL_GPL(extcon_sync);
>>     /**
>>    * extcon_get_state() - Get the state of a external connector.
>> @@ -493,17 +467,22 @@ EXPORT_SYMBOL_GPL(extcon_get_state);
>>     /**
>>    * extcon_set_state() - Set the state of a external connector.
>> + *            without a notification.
>>    * @edev:        the extcon device that has the cable.
>>    * @id:            the unique id of each external connector
>>    *            in extcon enumeration.
>>    * @state:        the new cable status. The default semantics is
>>    *            true: attached / false: detached.
>> + *
>> + * This function only set the state of a external connector without
>> + * a notification. To synchronize the data of a external connector,
>> + * use extcon_set_state_sync() and extcon_sync().
>>    */
>>   int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>                   bool cable_state)
>>   {
>> -    u32 state;
>> -    int index;
>> +    unsigned long flags;
>> +    int index, ret = 0;
>>         if (!edev)
>>           return -EINVAL;
>> @@ -515,6 +494,18 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>       if (edev->max_supported && edev->max_supported <= index)
>>           return -EINVAL;
>>   +    spin_lock_irqsave(&edev->lock, flags);
>> +
>> +    /* Check whether the external connector's state is changed. */
>> +    if (!is_extcon_changed(edev, index, cable_state))
>> +        goto out;
>> +
>> +    if (check_mutually_exclusive(edev,
>> +        (edev->state & ~(1 << index)) | (cable_state & (1 << index)))) {
>> +        ret = -EPERM;
>> +        goto out;
>> +    }
>> +
>>       /*
>>        * Initialize the value of extcon property before setting
>>        * the detached state for an external connector.
>> @@ -522,13 +513,44 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>       if (!cable_state)
>>           init_property(edev, id, index);
>>   -    /* Set the state for external connector as the detached state. */
>> -    state = cable_state ? (1 << index) : 0;
>> -    return extcon_update_state(edev, 1 << index, state);
>> +    /* Update the state for a external connector. */
>> +    if (cable_state)
>> +        edev->state |= (1 << index);
>> +    else
>> +        edev->state &= ~(1 << index);
>> +out:
>> +    spin_unlock_irqrestore(&edev->lock, flags);
>> +
>> +    return ret;
>>   }
>>   EXPORT_SYMBOL_GPL(extcon_set_state);
>>     /**
>> + * extcon_set_state_sync() - Set the state of a external connector
>> + *            with a notification.
>> + * @edev:        the extcon device that has the cable.
>> + * @id:            the unique id of each external connector
>> + *            in extcon enumeration.
>> + * @state:        the new cable status. The default semantics is
>> + *            true: attached / false: detached.
>> + *
>> + * This function set the state of external connector and synchronize the data
>> + * by usning a notification.
>> + */
>> +int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>> +                bool cable_state)
>> +{
>> +    int ret;
>> +
>> +    ret = extcon_set_state(edev, id, cable_state);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return extcon_sync(edev, id);
> So, Regardless of whether the state change, the notifier chain will be called,
> If this function can decide whether to call a notice, according to the state change. I think it would be better.
> The old extcon_set_cable_state_ was working like this.

OK. I'll modify it on next version.

[snip]

Regards,
Chanwoo Choi

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ