linux/drivers/uwb/radio.c
<<
>>
Prefs
   1/*
   2 * UWB radio (channel) management.
   3 *
   4 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License version
   8 * 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18#include <linux/kernel.h>
  19#include <linux/uwb.h>
  20#include <linux/export.h>
  21
  22#include "uwb-internal.h"
  23
  24
  25static int uwb_radio_select_channel(struct uwb_rc *rc)
  26{
  27        /*
  28         * Default to channel 9 (BG1, TFC1) unless the user has
  29         * selected a specific channel or there are no active PALs.
  30         */
  31        if (rc->active_pals == 0)
  32                return -1;
  33        if (rc->beaconing_forced)
  34                return rc->beaconing_forced;
  35        return 9;
  36}
  37
  38
  39/*
  40 * Notify all active PALs that the channel has changed.
  41 */
  42static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel)
  43{
  44        struct uwb_pal *pal;
  45
  46        list_for_each_entry(pal, &rc->pals, node) {
  47                if (pal->channel && channel != pal->channel) {
  48                        pal->channel = channel;
  49                        if (pal->channel_changed)
  50                                pal->channel_changed(pal, pal->channel);
  51                }
  52        }
  53}
  54
  55/*
  56 * Change to a new channel and notify any active PALs of the new
  57 * channel.
  58 *
  59 * When stopping the radio, PALs need to be notified first so they can
  60 * terminate any active reservations.
  61 */
  62static int uwb_radio_change_channel(struct uwb_rc *rc, int channel)
  63{
  64        int ret = 0;
  65        struct device *dev = &rc->uwb_dev.dev;
  66
  67        dev_dbg(dev, "%s: channel = %d, rc->beaconing = %d\n", __func__,
  68                channel, rc->beaconing);
  69
  70        if (channel == -1)
  71                uwb_radio_channel_changed(rc, channel);
  72
  73        if (channel != rc->beaconing) {
  74                if (rc->beaconing != -1 && channel != -1) {
  75                        /*
  76                         * FIXME: should signal the channel change
  77                         * with a Channel Change IE.
  78                         */
  79                        ret = uwb_radio_change_channel(rc, -1);
  80                        if (ret < 0)
  81                                return ret;
  82                }
  83                ret = uwb_rc_beacon(rc, channel, 0);
  84        }
  85
  86        if (channel != -1)
  87                uwb_radio_channel_changed(rc, rc->beaconing);
  88
  89        return ret;
  90}
  91
  92/**
  93 * uwb_radio_start - request that the radio be started
  94 * @pal: the PAL making the request.
  95 *
  96 * If the radio is not already active, a suitable channel is selected
  97 * and beacons are started.
  98 */
  99int uwb_radio_start(struct uwb_pal *pal)
 100{
 101        struct uwb_rc *rc = pal->rc;
 102        int ret = 0;
 103
 104        mutex_lock(&rc->uwb_dev.mutex);
 105
 106        if (!pal->channel) {
 107                pal->channel = -1;
 108                rc->active_pals++;
 109                ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
 110        }
 111
 112        mutex_unlock(&rc->uwb_dev.mutex);
 113        return ret;
 114}
 115EXPORT_SYMBOL_GPL(uwb_radio_start);
 116
 117/**
 118 * uwb_radio_stop - request that the radio be stopped.
 119 * @pal: the PAL making the request.
 120 *
 121 * Stops the radio if no other PAL is making use of it.
 122 */
 123void uwb_radio_stop(struct uwb_pal *pal)
 124{
 125        struct uwb_rc *rc = pal->rc;
 126
 127        mutex_lock(&rc->uwb_dev.mutex);
 128
 129        if (pal->channel) {
 130                rc->active_pals--;
 131                uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
 132                pal->channel = 0;
 133        }
 134
 135        mutex_unlock(&rc->uwb_dev.mutex);
 136}
 137EXPORT_SYMBOL_GPL(uwb_radio_stop);
 138
 139/*
 140 * uwb_radio_force_channel - force a specific channel to be used
 141 * @rc: the radio controller.
 142 * @channel: the channel to use; -1 to force the radio to stop; 0 to
 143 *   use the default channel selection algorithm.
 144 */
 145int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
 146{
 147        int ret = 0;
 148
 149        mutex_lock(&rc->uwb_dev.mutex);
 150
 151        rc->beaconing_forced = channel;
 152        ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
 153
 154        mutex_unlock(&rc->uwb_dev.mutex);
 155        return ret;
 156}
 157
 158/*
 159 * uwb_radio_setup - setup the radio manager
 160 * @rc: the radio controller.
 161 *
 162 * The radio controller is reset to ensure it's in a known state
 163 * before it's used.
 164 */
 165int uwb_radio_setup(struct uwb_rc *rc)
 166{
 167        return uwb_rc_reset(rc);
 168}
 169
 170/*
 171 * uwb_radio_reset_state - reset any radio manager state
 172 * @rc: the radio controller.
 173 *
 174 * All internal radio manager state is reset to values corresponding
 175 * to a reset radio controller.
 176 */
 177void uwb_radio_reset_state(struct uwb_rc *rc)
 178{
 179        struct uwb_pal *pal;
 180
 181        mutex_lock(&rc->uwb_dev.mutex);
 182
 183        list_for_each_entry(pal, &rc->pals, node) {
 184                if (pal->channel) {
 185                        pal->channel = -1;
 186                        if (pal->channel_changed)
 187                                pal->channel_changed(pal, -1);
 188                }
 189        }
 190
 191        rc->beaconing = -1;
 192        rc->scanning = -1;
 193
 194        mutex_unlock(&rc->uwb_dev.mutex);
 195}
 196
 197/*
 198 * uwb_radio_shutdown - shutdown the radio manager
 199 * @rc: the radio controller.
 200 *
 201 * The radio controller is reset.
 202 */
 203void uwb_radio_shutdown(struct uwb_rc *rc)
 204{
 205        uwb_radio_reset_state(rc);
 206        uwb_rc_reset(rc);
 207}
 208