@@ -279,14 +279,11 @@ static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index)
279
279
return !!(edev -> state & BIT (index ));
280
280
}
281
281
282
- static bool is_extcon_changed (u32 prev , u32 new , int idx , bool * attached )
282
+ static bool is_extcon_changed (struct extcon_dev * edev , int index ,
283
+ bool new_state )
283
284
{
284
- if (((prev >> idx ) & 0x1 ) != ((new >> idx ) & 0x1 )) {
285
- * attached = ((new >> idx ) & 0x1 ) ? true : false;
286
- return true;
287
- }
288
-
289
- return false;
285
+ int state = !!(edev -> state & BIT (index ));
286
+ return (state != new_state );
290
287
}
291
288
292
289
static bool is_extcon_property_supported (unsigned int id , unsigned int prop )
@@ -402,21 +399,13 @@ static ssize_t cable_state_show(struct device *dev,
402
399
}
403
400
404
401
/**
405
- * extcon_update_state() - Update the cable attach states of the extcon device
406
- * only for the masked bits.
407
- * @edev: the extcon device
408
- * @mask: the bit mask to designate updated bits.
409
- * @state: new cable attach status for @edev
410
- *
411
- * Changing the state sends uevent with environment variable containing
412
- * the name of extcon device (envp[0]) and the state output (envp[1]).
413
- * Tizen uses this format for extcon device to get events from ports.
414
- * Android uses this format as well.
402
+ * extcon_sync() - Synchronize the states for both the attached/detached
403
+ * @edev: the extcon device that has the cable.
415
404
*
416
- * Note that the notifier provides which bits are changed in the state
417
- * variable with the val parameter (second) to the callback.
405
+ * This function send a notification to synchronize the all states of a
406
+ * specific external connector
418
407
*/
419
- static int extcon_update_state (struct extcon_dev * edev , u32 mask , u32 state )
408
+ int extcon_sync (struct extcon_dev * edev , unsigned int id )
420
409
{
421
410
char name_buf [120 ];
422
411
char state_buf [120 ];
@@ -425,73 +414,58 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
425
414
int env_offset = 0 ;
426
415
int length ;
427
416
int index ;
417
+ int state ;
428
418
unsigned long flags ;
429
- bool attached ;
430
419
431
420
if (!edev )
432
421
return - EINVAL ;
433
422
423
+ index = find_cable_index_by_id (edev , id );
424
+ if (index < 0 )
425
+ return index ;
426
+
434
427
spin_lock_irqsave (& edev -> lock , flags );
435
428
436
- if ( edev -> state != (( edev -> state & ~ mask ) | ( state & mask ))) {
437
- u32 old_state ;
429
+ state = !!( edev -> state & BIT ( index ));
430
+ raw_notifier_call_chain ( & edev -> nh [ index ], state , edev ) ;
438
431
439
- if ( check_mutually_exclusive ( edev , ( edev -> state & ~ mask ) |
440
- ( state & mask ))) {
441
- spin_unlock_irqrestore ( & edev -> lock , flags );
442
- return - EPERM ;
443
- }
432
+ /* This could be in interrupt handler */
433
+ prop_buf = ( char * ) get_zeroed_page ( GFP_ATOMIC );
434
+ if (! prop_buf ) {
435
+ /* Unlock early before uevent */
436
+ spin_unlock_irqrestore ( & edev -> lock , flags );
444
437
445
- old_state = edev -> state ;
446
- edev -> state &= ~mask ;
447
- edev -> state |= state & mask ;
438
+ dev_err (& edev -> dev , "out of memory in extcon_set_state\n" );
439
+ kobject_uevent (& edev -> dev .kobj , KOBJ_CHANGE );
448
440
449
- for (index = 0 ; index < edev -> max_supported ; index ++ ) {
450
- if (is_extcon_changed (old_state , edev -> state , index ,
451
- & attached ))
452
- raw_notifier_call_chain (& edev -> nh [index ],
453
- attached , edev );
454
- }
455
-
456
- /* This could be in interrupt handler */
457
- prop_buf = (char * )get_zeroed_page (GFP_ATOMIC );
458
- if (prop_buf ) {
459
- length = name_show (& edev -> dev , NULL , prop_buf );
460
- if (length > 0 ) {
461
- if (prop_buf [length - 1 ] == '\n' )
462
- prop_buf [length - 1 ] = 0 ;
463
- snprintf (name_buf , sizeof (name_buf ),
464
- "NAME=%s" , prop_buf );
465
- envp [env_offset ++ ] = name_buf ;
466
- }
467
- length = state_show (& edev -> dev , NULL , prop_buf );
468
- if (length > 0 ) {
469
- if (prop_buf [length - 1 ] == '\n' )
470
- prop_buf [length - 1 ] = 0 ;
471
- snprintf (state_buf , sizeof (state_buf ),
472
- "STATE=%s" , prop_buf );
473
- envp [env_offset ++ ] = state_buf ;
474
- }
475
- envp [env_offset ] = NULL ;
476
- /* Unlock early before uevent */
477
- spin_unlock_irqrestore (& edev -> lock , flags );
441
+ return 0 ;
442
+ }
478
443
479
- kobject_uevent_env (& edev -> dev .kobj , KOBJ_CHANGE , envp );
480
- free_page ((unsigned long )prop_buf );
481
- } else {
482
- /* Unlock early before uevent */
483
- spin_unlock_irqrestore (& edev -> lock , flags );
444
+ length = name_show (& edev -> dev , NULL , prop_buf );
445
+ if (length > 0 ) {
446
+ if (prop_buf [length - 1 ] == '\n' )
447
+ prop_buf [length - 1 ] = 0 ;
448
+ snprintf (name_buf , sizeof (name_buf ), "NAME=%s" , prop_buf );
449
+ envp [env_offset ++ ] = name_buf ;
450
+ }
484
451
485
- dev_err (& edev -> dev , "out of memory in extcon_set_state\n" );
486
- kobject_uevent ( & edev -> dev . kobj , KOBJ_CHANGE );
487
- }
488
- } else {
489
- /* No changes */
490
- spin_unlock_irqrestore ( & edev -> lock , flags ) ;
452
+ length = state_show (& edev -> dev , NULL , prop_buf );
453
+ if ( length > 0 ) {
454
+ if ( prop_buf [ length - 1 ] == '\n' )
455
+ prop_buf [ length - 1 ] = 0 ;
456
+ snprintf ( state_buf , sizeof ( state_buf ), "STATE=%s" , prop_buf );
457
+ envp [ env_offset ++ ] = state_buf ;
491
458
}
459
+ envp [env_offset ] = NULL ;
460
+
461
+ /* Unlock early before uevent */
462
+ spin_unlock_irqrestore (& edev -> lock , flags );
463
+ kobject_uevent_env (& edev -> dev .kobj , KOBJ_CHANGE , envp );
464
+ free_page ((unsigned long )prop_buf );
492
465
493
466
return 0 ;
494
467
}
468
+ EXPORT_SYMBOL_GPL (extcon_sync );
495
469
496
470
/**
497
471
* extcon_get_state() - Get the state of a external connector.
@@ -520,17 +494,22 @@ EXPORT_SYMBOL_GPL(extcon_get_state);
520
494
521
495
/**
522
496
* extcon_set_state() - Set the state of a external connector.
497
+ * without a notification.
523
498
* @edev: the extcon device that has the cable.
524
499
* @id: the unique id of each external connector
525
500
* in extcon enumeration.
526
501
* @state: the new cable status. The default semantics is
527
502
* true: attached / false: detached.
503
+ *
504
+ * This function only set the state of a external connector without
505
+ * a notification. To synchronize the data of a external connector,
506
+ * use extcon_set_state_sync() and extcon_sync().
528
507
*/
529
508
int extcon_set_state (struct extcon_dev * edev , unsigned int id ,
530
509
bool cable_state )
531
510
{
532
- u32 state ;
533
- int index ;
511
+ unsigned long flags ;
512
+ int index , ret = 0 ;
534
513
535
514
if (!edev )
536
515
return - EINVAL ;
@@ -539,18 +518,74 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id,
539
518
if (index < 0 )
540
519
return index ;
541
520
521
+ spin_lock_irqsave (& edev -> lock , flags );
522
+
523
+ /* Check whether the external connector's state is changed. */
524
+ if (!is_extcon_changed (edev , index , cable_state ))
525
+ goto out ;
526
+
527
+ if (check_mutually_exclusive (edev ,
528
+ (edev -> state & ~BIT (index )) | (cable_state & BIT (index )))) {
529
+ ret = - EPERM ;
530
+ goto out ;
531
+ }
532
+
542
533
/*
543
534
* Initialize the value of extcon property before setting
544
535
* the detached state for an external connector.
545
536
*/
546
537
if (!cable_state )
547
538
init_property (edev , id , index );
548
539
549
- state = cable_state ? (1 << index ) : 0 ;
550
- return extcon_update_state (edev , 1 << index , state );
540
+ /* Update the state for a external connector. */
541
+ if (cable_state )
542
+ edev -> state |= BIT (index );
543
+ else
544
+ edev -> state &= ~(BIT (index ));
545
+ out :
546
+ spin_unlock_irqrestore (& edev -> lock , flags );
547
+
548
+ return ret ;
551
549
}
552
550
EXPORT_SYMBOL_GPL (extcon_set_state );
553
551
552
+ /**
553
+ * extcon_set_state_sync() - Set the state of a external connector
554
+ * with a notification.
555
+ * @edev: the extcon device that has the cable.
556
+ * @id: the unique id of each external connector
557
+ * in extcon enumeration.
558
+ * @state: the new cable status. The default semantics is
559
+ * true: attached / false: detached.
560
+ *
561
+ * This function set the state of external connector and synchronize the data
562
+ * by usning a notification.
563
+ */
564
+ int extcon_set_state_sync (struct extcon_dev * edev , unsigned int id ,
565
+ bool cable_state )
566
+ {
567
+ int ret , index ;
568
+ unsigned long flags ;
569
+
570
+ index = find_cable_index_by_id (edev , id );
571
+ if (index < 0 )
572
+ return index ;
573
+
574
+ /* Check whether the external connector's state is changed. */
575
+ spin_lock_irqsave (& edev -> lock , flags );
576
+ ret = is_extcon_changed (edev , index , cable_state );
577
+ spin_unlock_irqrestore (& edev -> lock , flags );
578
+ if (!ret )
579
+ return 0 ;
580
+
581
+ ret = extcon_set_state (edev , id , cable_state );
582
+ if (ret < 0 )
583
+ return ret ;
584
+
585
+ return extcon_sync (edev , id );
586
+ }
587
+ EXPORT_SYMBOL_GPL (extcon_set_state_sync );
588
+
554
589
/**
555
590
* extcon_get_property() - Get the property value of a specific cable.
556
591
* @edev: the extcon device that has the cable.
@@ -701,6 +736,31 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id,
701
736
}
702
737
EXPORT_SYMBOL_GPL (extcon_set_property );
703
738
739
+ /**
740
+ * extcon_set_property_sync() - Set the property value of a specific cable
741
+ with a notification.
742
+ * @prop_val: the pointer including the new value of property.
743
+ *
744
+ * When setting the property value of external connector, the external connector
745
+ * should be attached. The each property should be included in the list of
746
+ * supported properties according to the type of external connectors.
747
+ *
748
+ * Returns 0 if success or error number if fail
749
+ */
750
+ int extcon_set_property_sync (struct extcon_dev * edev , unsigned int id ,
751
+ unsigned int prop ,
752
+ union extcon_property_value prop_val )
753
+ {
754
+ int ret ;
755
+
756
+ ret = extcon_set_property (edev , id , prop , prop_val );
757
+ if (ret < 0 )
758
+ return ret ;
759
+
760
+ return extcon_sync (edev , id );
761
+ }
762
+ EXPORT_SYMBOL_GPL (extcon_set_property_sync );
763
+
704
764
/**
705
765
* extcon_get_property_capability() - Get the capability of property
706
766
* of an external connector.
0 commit comments