linux/drivers/w1/w1_family.c
<<
>>
Prefs
   1/*
   2 *      w1_family.c
   3 *
   4 * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
   5 *
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21
  22#include <linux/spinlock.h>
  23#include <linux/list.h>
  24#include <linux/sched.h>        /* schedule_timeout() */
  25#include <linux/delay.h>
  26#include <linux/export.h>
  27
  28#include "w1_family.h"
  29#include "w1.h"
  30
  31DEFINE_SPINLOCK(w1_flock);
  32static LIST_HEAD(w1_families);
  33
  34/**
  35 * w1_register_family() - register a device family driver
  36 * @newf:       family to register
  37 */
  38int w1_register_family(struct w1_family *newf)
  39{
  40        struct list_head *ent, *n;
  41        struct w1_family *f;
  42        int ret = 0;
  43
  44        spin_lock(&w1_flock);
  45        list_for_each_safe(ent, n, &w1_families) {
  46                f = list_entry(ent, struct w1_family, family_entry);
  47
  48                if (f->fid == newf->fid) {
  49                        ret = -EEXIST;
  50                        break;
  51                }
  52        }
  53
  54        if (!ret) {
  55                atomic_set(&newf->refcnt, 0);
  56                list_add_tail(&newf->family_entry, &w1_families);
  57        }
  58        spin_unlock(&w1_flock);
  59
  60        /* check default devices against the new set of drivers */
  61        w1_reconnect_slaves(newf, 1);
  62
  63        return ret;
  64}
  65
  66/**
  67 * w1_unregister_family() - unregister a device family driver
  68 * @fent:       family to unregister
  69 */
  70void w1_unregister_family(struct w1_family *fent)
  71{
  72        struct list_head *ent, *n;
  73        struct w1_family *f;
  74
  75        spin_lock(&w1_flock);
  76        list_for_each_safe(ent, n, &w1_families) {
  77                f = list_entry(ent, struct w1_family, family_entry);
  78
  79                if (f->fid == fent->fid) {
  80                        list_del(&fent->family_entry);
  81                        break;
  82                }
  83        }
  84        spin_unlock(&w1_flock);
  85
  86        /* deatch devices using this family code */
  87        w1_reconnect_slaves(fent, 0);
  88
  89        while (atomic_read(&fent->refcnt)) {
  90                pr_info("Waiting for family %u to become free: refcnt=%d.\n",
  91                                fent->fid, atomic_read(&fent->refcnt));
  92
  93                if (msleep_interruptible(1000))
  94                        flush_signals(current);
  95        }
  96}
  97
  98/*
  99 * Should be called under w1_flock held.
 100 */
 101struct w1_family * w1_family_registered(u8 fid)
 102{
 103        struct list_head *ent, *n;
 104        struct w1_family *f = NULL;
 105        int ret = 0;
 106
 107        list_for_each_safe(ent, n, &w1_families) {
 108                f = list_entry(ent, struct w1_family, family_entry);
 109
 110                if (f->fid == fid) {
 111                        ret = 1;
 112                        break;
 113                }
 114        }
 115
 116        return (ret) ? f : NULL;
 117}
 118
 119static void __w1_family_put(struct w1_family *f)
 120{
 121        atomic_dec(&f->refcnt);
 122}
 123
 124void w1_family_put(struct w1_family *f)
 125{
 126        spin_lock(&w1_flock);
 127        __w1_family_put(f);
 128        spin_unlock(&w1_flock);
 129}
 130
 131#if 0
 132void w1_family_get(struct w1_family *f)
 133{
 134        spin_lock(&w1_flock);
 135        __w1_family_get(f);
 136        spin_unlock(&w1_flock);
 137}
 138#endif  /*  0  */
 139
 140void __w1_family_get(struct w1_family *f)
 141{
 142        smp_mb__before_atomic();
 143        atomic_inc(&f->refcnt);
 144        smp_mb__after_atomic();
 145}
 146
 147EXPORT_SYMBOL(w1_unregister_family);
 148EXPORT_SYMBOL(w1_register_family);
 149