linux/drivers/usb/wusbcore/mmc.c History
<<
>>
Prefs
   1/*
   2 * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
   3 * MMC (Microscheduled Management Command) handling
   4 *
   5 * Copyright (C) 2005-2006 Intel Corporation
   6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License version
  10 * 2 as published by the Free Software Foundation.
  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., 51 Franklin Street, Fifth Floor, Boston, MA
  20 * 02110-1301, USA.
  21 *
  22 *
  23 * WUIEs and MMC IEs...well, they are almost the same at the end. MMC
  24 * IEs are Wireless USB IEs that go into the MMC period...[what is
  25 * that? look in Design-overview.txt].
  26 *
  27 *
  28 * This is a simple subsystem to keep track of which IEs are being
  29 * sent by the host in the MMC period.
  30 *
  31 * For each WUIE we ask to send, we keep it in an array, so we can
  32 * request its removal later, or replace the content. They are tracked
  33 * by pointer, so be sure to use the same pointer if you want to
  34 * remove it or update the contents.
  35 *
  36 * FIXME:
  37 *  - add timers that autoremove intervalled IEs?
  38 */
  39#include <linux/usb/wusb.h>
  40#include "wusbhc.h"
  41
  42/* Initialize the MMCIEs handling mechanism */
  43int wusbhc_mmcie_create(struct wusbhc *wusbhc)
  44{
  45        u8 mmcies = wusbhc->mmcies_max;
  46        wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
  47        if (wusbhc->mmcie == NULL)
  48                return -ENOMEM;
  49        mutex_init(&wusbhc->mmcie_mutex);
  50        return 0;
  51}
  52
  53/* Release resources used by the MMCIEs handling mechanism */
  54void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
  55{
  56        kfree(wusbhc->mmcie);
  57}
  58
  59/*
  60 * Add or replace an MMC Wireless USB IE.
  61 *
  62 * @interval:    See WUSB1.0[8.5.3.1]
  63 * @repeat_cnt:  See WUSB1.0[8.5.3.1]
  64 * @handle:      See WUSB1.0[8.5.3.1]
  65 * @wuie:        Pointer to the header of the WUSB IE data to add.
  66 *               MUST BE allocated in a kmalloc buffer (no stack or
  67 *               vmalloc).
  68 *               THE CALLER ALWAYS OWNS THE POINTER (we don't free it
  69 *               on remove, we just forget about it).
  70 * @returns:     0 if ok, < 0 errno code on error.
  71 *
  72 * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
  73 * first free spot and (b) if @wuie is already in the array (aka:
  74 * transmitted in the MMCs) the spot were it is.
  75 *
  76 * If present, we "overwrite it" (update).
  77 *
  78 *
  79 * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
  80 *       The host uses the handle as the 'sort' index. We
  81 *       allocate the last one always for the WUIE_ID_HOST_INFO, and
  82 *       the rest, first come first serve in inverse order.
  83 *
  84 *       Host software must make sure that it adds the other IEs in
  85 *       the right order... the host hardware is responsible for
  86 *       placing the WCTA IEs in the right place with the other IEs
  87 *       set by host software.
  88 *
  89 * NOTE: we can access wusbhc->wa_descr without locking because it is
  90 *       read only.
  91 */
  92int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
  93                     struct wuie_hdr *wuie)
  94{
  95        int result = -ENOBUFS;
  96        unsigned handle, itr;
  97
  98        /* Search a handle, taking into account the ordering */
  99        mutex_lock(&wusbhc->mmcie_mutex);
 100        switch (wuie->bIEIdentifier) {
 101        case WUIE_ID_HOST_INFO:
 102                /* Always last */
 103                handle = wusbhc->mmcies_max - 1;
 104                break;
 105        case WUIE_ID_ISOCH_DISCARD:
 106                dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
 107                        "unimplemented\n", wuie->bIEIdentifier);
 108                result = -ENOSYS;
 109                goto error_unlock;
 110        default:
 111                /* search for it or find the last empty slot */
 112                handle = ~0;
 113                for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
 114                        if (wusbhc->mmcie[itr] == wuie) {
 115                                handle = itr;
 116                                break;
 117                        }
 118                        if (wusbhc->mmcie[itr] == NULL)
 119                                handle = itr;
 120                }
 121                if (handle == ~0)
 122                        goto error_unlock;
 123        }
 124        result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
 125                                     wuie);
 126        if (result >= 0)
 127                wusbhc->mmcie[handle] = wuie;
 128error_unlock:
 129        mutex_unlock(&wusbhc->mmcie_mutex);
 130        return result;
 131}
 132EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
 133
 134/*
 135 * Remove an MMC IE previously added with wusbhc_mmcie_set()
 136 *
 137 * @wuie        Pointer used to add the WUIE
 138 */
 139void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
 140{
 141        int result;
 142        unsigned handle, itr;
 143
 144        mutex_lock(&wusbhc->mmcie_mutex);
 145        for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
 146                if (wusbhc->mmcie[itr] == wuie) {
 147                        handle = itr;
 148                        goto found;
 149                }
 150        }
 151        mutex_unlock(&wusbhc->mmcie_mutex);
 152        return;
 153
 154found:
 155        result = (wusbhc->mmcie_rm)(wusbhc, handle);
 156        if (result == 0)
 157                wusbhc->mmcie[itr] = NULL;
 158        mutex_unlock(&wusbhc->mmcie_mutex);
 159}
 160EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
 161
 162static int wusbhc_mmc_start(struct wusbhc *wusbhc)
 163{
 164        int ret;
 165
 166        mutex_lock(&wusbhc->mutex);
 167        ret = wusbhc->start(wusbhc);
 168        if (ret >= 0)
 169                wusbhc->active = 1;
 170        mutex_unlock(&wusbhc->mutex);
 171
 172        return ret;
 173}
 174
 175static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
 176{
 177        mutex_lock(&wusbhc->mutex);
 178        wusbhc->active = 0;
 179        wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
 180        mutex_unlock(&wusbhc->mutex);
 181}
 182
 183/*
 184 * wusbhc_start - start transmitting MMCs and accepting connections
 185 * @wusbhc: the HC to start
 186 *
 187 * Establishes a cluster reservation, enables device connections, and
 188 * starts MMCs with appropriate DNTS parameters.
 189 */
 190int wusbhc_start(struct wusbhc *wusbhc)
 191{
 192        int result;
 193        struct device *dev = wusbhc->dev;
 194
 195        WARN_ON(wusbhc->wuie_host_info != NULL);
 196
 197        result = wusbhc_rsv_establish(wusbhc);
 198        if (result < 0) {
 199                dev_err(dev, "cannot establish cluster reservation: %d\n",
 200                        result);
 201                goto error_rsv_establish;
 202        }
 203
 204        result = wusbhc_devconnect_start(wusbhc);
 205        if (result < 0) {
 206                dev_err(dev, "error enabling device connections: %d\n", result);
 207                goto error_devconnect_start;
 208        }
 209
 210        result = wusbhc_sec_start(wusbhc);
 211        if (result < 0) {
 212                dev_err(dev, "error starting security in the HC: %d\n", result);
 213                goto error_sec_start;
 214        }
 215        /* FIXME: the choice of the DNTS parameters is somewhat
 216         * arbitrary */
 217        result = wusbhc->set_num_dnts(wusbhc, 0, 15);
 218        if (result < 0) {
 219                dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
 220                goto error_set_num_dnts;
 221        }
 222        result = wusbhc_mmc_start(wusbhc);
 223        if (result < 0) {
 224                dev_err(dev, "error starting wusbch: %d\n", result);
 225                goto error_wusbhc_start;
 226        }
 227
 228        return 0;
 229
 230error_wusbhc_start:
 231        wusbhc_sec_stop(wusbhc);
 232error_set_num_dnts:
 233error_sec_start:
 234        wusbhc_devconnect_stop(wusbhc);
 235error_devconnect_start:
 236        wusbhc_rsv_terminate(wusbhc);
 237error_rsv_establish:
 238        return result;
 239}
 240
 241/*
 242 * wusbhc_stop - stop transmitting MMCs
 243 * @wusbhc: the HC to stop
 244 *
 245 * Stops the WUSB channel and removes the cluster reservation.
 246 */
 247void wusbhc_stop(struct wusbhc *wusbhc)
 248{
 249        wusbhc_mmc_stop(wusbhc);
 250        wusbhc_sec_stop(wusbhc);
 251        wusbhc_devconnect_stop(wusbhc);
 252        wusbhc_rsv_terminate(wusbhc);
 253}
 254
 255/*
 256 * Set/reset/update a new CHID
 257 *
 258 * Depending on the previous state of the MMCs, start, stop or change
 259 * the sent MMC. This effectively switches the host controller on and
 260 * off (radio wise).
 261 */
 262int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
 263{
 264        int result = 0;
 265
 266        if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0)
 267                chid = NULL;
 268
 269        mutex_lock(&wusbhc->mutex);
 270        if (chid) {
 271                if (wusbhc->active) {
 272                        mutex_unlock(&wusbhc->mutex);
 273                        return -EBUSY;
 274                }
 275                wusbhc->chid = *chid;
 276        }
 277        mutex_unlock(&wusbhc->mutex);
 278
 279        if (chid)
 280                result = uwb_radio_start(&wusbhc->pal);
 281        else
 282                uwb_radio_stop(&wusbhc->pal);
 283        return result;
 284}
 285EXPORT_SYMBOL_GPL(wusbhc_chid_set);
 286
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.