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
  66        if (channel == -1)
  67                uwb_radio_channel_changed(rc, channel);
  68
  69        if (channel != rc->beaconing) {
  70                if (rc->beaconing != -1 && channel != -1) {
  71                        /*
  72                         * FIXME: should signal the channel change
  73                         * with a Channel Change IE.
  74                         */
  75                        ret = uwb_radio_change_channel(rc, -1);
  76                        if (ret < 0)
  77                                return ret;
  78                }
  79                ret = uwb_rc_beacon(rc, channel, 0);
  80        }
  81
  82        if (channel != -1)
  83                uwb_radio_channel_changed(rc, rc->beaconing);
  84
  85        return ret;
  86}
  87
  88/**
  89 * uwb_radio_start - request that the radio be started
  90 * @pal: the PAL making the request.
  91 *
  92 * If the radio is not already active, aa suitable channel is selected
  93 * and beacons are started.
  94 */
  95int uwb_radio_start(struct uwb_pal *pal)
  96{
  97        struct uwb_rc *rc = pal->rc;
  98        int ret = 0;
  99
 100        mutex_lock(&rc->uwb_dev.mutex);
 101
 102        if (!pal->channel) {
 103                pal->channel = -1;
 104                rc->active_pals++;
 105                ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
 106        }
 107
 108        mutex_unlock(&rc->uwb_dev.mutex);
 109        return ret;
 110}
 111EXPORT_SYMBOL_GPL(uwb_radio_start);
 112
 113/**
 114 * uwb_radio_stop - request tha the radio be stopped.
 115 * @pal: the PAL making the request.
 116 *
 117 * Stops the radio if no other PAL is making use of it.
 118 */
 119void uwb_radio_stop(struct uwb_pal *pal)
 120{
 121        struct uwb_rc *rc = pal->rc;
 122
 123        mutex_lock(&rc->uwb_dev.mutex);
 124
 125        if (pal->channel) {
 126                rc->active_pals--;
 127                uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
 128                pal->channel = 0;
 129        }
 130
 131        mutex_unlock(&rc->uwb_dev.mutex);
 132}
 133EXPORT_SYMBOL_GPL(uwb_radio_stop);
 134
 135/*
 136 * uwb_radio_force_channel - force a specific channel to be used
 137 * @rc: the radio controller.
 138 * @channel: the channel to use; -1 to force the radio to stop; 0 to
 139 *   use the default channel selection algorithm.
 140 */
 141int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
 142{
 143        int ret = 0;
 144
 145        mutex_lock(&rc->uwb_dev.mutex);
 146
 147        rc->beaconing_forced = channel;
 148        ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
 149
 150        mutex_unlock(&rc->uwb_dev.mutex);
 151        return ret;
 152}
 153
 154/*
 155 * uwb_radio_setup - setup the radio manager
 156 * @rc: the radio controller.
 157 *
 158 * The radio controller is reset to ensure it's in a known state
 159 * before it's used.
 160 */
 161int uwb_radio_setup(struct uwb_rc *rc)
 162{
 163        return uwb_rc_reset(rc);
 164}
 165
 166/*
 167 * uwb_radio_reset_state - reset any radio manager state
 168 * @rc: the radio controller.
 169 *
 170 * All internal radio manager state is reset to values corresponding
 171 * to a reset radio controller.
 172 */
 173void uwb_radio_reset_state(struct uwb_rc *rc)
 174{
 175        struct uwb_pal *pal;
 176
 177        mutex_lock(&rc->uwb_dev.mutex);
 178
 179        list_for_each_entry(pal, &rc->pals, node) {
 180                if (pal->channel) {
 181                        pal->channel = -1;
 182                        if (pal->channel_changed)
 183                                pal->channel_changed(pal, -1);
 184                }
 185        }
 186
 187        rc->beaconing = -1;
 188        rc->scanning = -1;
 189
 190        mutex_unlock(&rc->uwb_dev.mutex);
 191}
 192
 193/*
 194 * uwb_radio_shutdown - shutdown the radio manager
 195 * @rc: the radio controller.
 196 *
 197 * The radio controller is reset.
 198 */
 199void uwb_radio_shutdown(struct uwb_rc *rc)
 200{
 201        uwb_radio_reset_state(rc);
 202        uwb_rc_reset(rc);
 203}
 204