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
  34int w1_register_family(struct w1_family *newf)
  35{
  36        struct list_head *ent, *n;
  37        struct w1_family *f;
  38        int ret = 0;
  39
  40        spin_lock(&w1_flock);
  41        list_for_each_safe(ent, n, &w1_families) {
  42                f = list_entry(ent, struct w1_family, family_entry);
  43
  44                if (f->fid == newf->fid) {
  45                        ret = -EEXIST;
  46                        break;
  47                }
  48        }
  49
  50        if (!ret) {
  51                atomic_set(&newf->refcnt, 0);
  52                list_add_tail(&newf->family_entry, &w1_families);
  53        }
  54        spin_unlock(&w1_flock);
  55
  56        /* check default devices against the new set of drivers */
  57        w1_reconnect_slaves(newf, 1);
  58
  59        return ret;
  60}
  61
  62void w1_unregister_family(struct w1_family *fent)
  63{
  64        struct list_head *ent, *n;
  65        struct w1_family *f;
  66
  67        spin_lock(&w1_flock);
  68        list_for_each_safe(ent, n, &w1_families) {
  69                f = list_entry(ent, struct w1_family, family_entry);
  70
  71                if (f->fid == fent->fid) {
  72                        list_del(&fent->family_entry);
  73                        break;
  74                }
  75        }
  76        spin_unlock(&w1_flock);
  77
  78        /* deatch devices using this family code */
  79        w1_reconnect_slaves(fent, 0);
  80
  81        while (atomic_read(&fent->refcnt)) {
  82                printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
  83                                fent->fid, atomic_read(&fent->refcnt));
  84
  85                if (msleep_interruptible(1000))
  86                        flush_signals(current);
  87        }
  88}
  89
  90/*
  91 * Should be called under w1_flock held.
  92 */
  93struct w1_family * w1_family_registered(u8 fid)
  94{
  95        struct list_head *ent, *n;
  96        struct w1_family *f = NULL;
  97        int ret = 0;
  98
  99        list_for_each_safe(ent, n, &w1_families) {
 100                f = list_entry(ent, struct w1_family, family_entry);
 101
 102                if (f->fid == fid) {
 103                        ret = 1;
 104                        break;
 105                }
 106        }
 107
 108        return (ret) ? f : NULL;
 109}
 110
 111static void __w1_family_put(struct w1_family *f)
 112{
 113        atomic_dec(&f->refcnt);
 114}
 115
 116void w1_family_put(struct w1_family *f)
 117{
 118        spin_lock(&w1_flock);
 119        __w1_family_put(f);
 120        spin_unlock(&w1_flock);
 121}
 122
 123#if 0
 124void w1_family_get(struct w1_family *f)
 125{
 126        spin_lock(&w1_flock);
 127        __w1_family_get(f);
 128        spin_unlock(&w1_flock);
 129}
 130#endif  /*  0  */
 131
 132void __w1_family_get(struct w1_family *f)
 133{
 134        smp_mb__before_atomic_inc();
 135        atomic_inc(&f->refcnt);
 136        smp_mb__after_atomic_inc();
 137}
 138
 139EXPORT_SYMBOL(w1_unregister_family);
 140EXPORT_SYMBOL(w1_register_family);
 141
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.