linux/drivers/w1/w1_family.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
   4 */
   5
   6#include <linux/spinlock.h>
   7#include <linux/list.h>
   8#include <linux/sched/signal.h>
   9#include <linux/delay.h>
  10#include <linux/export.h>
  11
  12#include "w1_internal.h"
  13
  14DEFINE_SPINLOCK(w1_flock);
  15static LIST_HEAD(w1_families);
  16
  17/**
  18 * w1_register_family() - register a device family driver
  19 * @newf:       family to register
  20 */
  21int w1_register_family(struct w1_family *newf)
  22{
  23        struct list_head *ent, *n;
  24        struct w1_family *f;
  25        int ret = 0;
  26
  27        spin_lock(&w1_flock);
  28        list_for_each_safe(ent, n, &w1_families) {
  29                f = list_entry(ent, struct w1_family, family_entry);
  30
  31                if (f->fid == newf->fid) {
  32                        ret = -EEXIST;
  33                        break;
  34                }
  35        }
  36
  37        if (!ret) {
  38                atomic_set(&newf->refcnt, 0);
  39                list_add_tail(&newf->family_entry, &w1_families);
  40        }
  41        spin_unlock(&w1_flock);
  42
  43        /* check default devices against the new set of drivers */
  44        w1_reconnect_slaves(newf, 1);
  45
  46        return ret;
  47}
  48EXPORT_SYMBOL(w1_register_family);
  49
  50/**
  51 * w1_unregister_family() - unregister a device family driver
  52 * @fent:       family to unregister
  53 */
  54void w1_unregister_family(struct w1_family *fent)
  55{
  56        struct list_head *ent, *n;
  57        struct w1_family *f;
  58
  59        spin_lock(&w1_flock);
  60        list_for_each_safe(ent, n, &w1_families) {
  61                f = list_entry(ent, struct w1_family, family_entry);
  62
  63                if (f->fid == fent->fid) {
  64                        list_del(&fent->family_entry);
  65                        break;
  66                }
  67        }
  68        spin_unlock(&w1_flock);
  69
  70        /* deatch devices using this family code */
  71        w1_reconnect_slaves(fent, 0);
  72
  73        while (atomic_read(&fent->refcnt)) {
  74                pr_info("Waiting for family %u to become free: refcnt=%d.\n",
  75                                fent->fid, atomic_read(&fent->refcnt));
  76
  77                if (msleep_interruptible(1000))
  78                        flush_signals(current);
  79        }
  80}
  81EXPORT_SYMBOL(w1_unregister_family);
  82
  83/*
  84 * Should be called under w1_flock held.
  85 */
  86struct w1_family * w1_family_registered(u8 fid)
  87{
  88        struct list_head *ent, *n;
  89        struct w1_family *f = NULL;
  90        int ret = 0;
  91
  92        list_for_each_safe(ent, n, &w1_families) {
  93                f = list_entry(ent, struct w1_family, family_entry);
  94
  95                if (f->fid == fid) {
  96                        ret = 1;
  97                        break;
  98                }
  99        }
 100
 101        return (ret) ? f : NULL;
 102}
 103
 104static void __w1_family_put(struct w1_family *f)
 105{
 106        atomic_dec(&f->refcnt);
 107}
 108
 109void w1_family_put(struct w1_family *f)
 110{
 111        spin_lock(&w1_flock);
 112        __w1_family_put(f);
 113        spin_unlock(&w1_flock);
 114}
 115
 116#if 0
 117void w1_family_get(struct w1_family *f)
 118{
 119        spin_lock(&w1_flock);
 120        __w1_family_get(f);
 121        spin_unlock(&w1_flock);
 122}
 123#endif  /*  0  */
 124
 125void __w1_family_get(struct w1_family *f)
 126{
 127        smp_mb__before_atomic();
 128        atomic_inc(&f->refcnt);
 129        smp_mb__after_atomic();
 130}
 131