2  * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
 
   3  * MMC (Microscheduled Management Command) handling
 
   5  * Copyright (C) 2005-2006 Intel Corporation
 
   6  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 
   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.
 
  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.
 
  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
 
  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].
 
  28  * This is a simple subsystem to keep track of which IEs are being
 
  29  * sent by the host in the MMC period.
 
  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.
 
  37  *  - add timers that autoremove intervalled IEs?
 
  39 #include <linux/usb/wusb.h>
 
  42 /* Initialize the MMCIEs handling mechanism */
 
  43 int wusbhc_mmcie_create(struct wusbhc *wusbhc)
 
  45         u8 mmcies = wusbhc->mmcies_max;
 
  46         wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
 
  47         if (wusbhc->mmcie == NULL)
 
  49         mutex_init(&wusbhc->mmcie_mutex);
 
  53 /* Release resources used by the MMCIEs handling mechanism */
 
  54 void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
 
  60  * Add or replace an MMC Wireless USB IE.
 
  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
 
  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.
 
  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.
 
  76  * If present, we "overwrite it" (update).
 
  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.
 
  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.
 
  89  * NOTE: we can access wusbhc->wa_descr without locking because it is
 
  92 int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
 
  93                      struct wuie_hdr *wuie)
 
  95         int result = -ENOBUFS;
 
  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:
 
 103                 handle = wusbhc->mmcies_max - 1;
 
 105         case WUIE_ID_ISOCH_DISCARD:
 
 106                 dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
 
 107                         "unimplemented\n", wuie->bIEIdentifier);
 
 111                 /* search for it or find the last empty slot */
 
 113                 for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
 
 114                         if (wusbhc->mmcie[itr] == wuie) {
 
 118                         if (wusbhc->mmcie[itr] == NULL)
 
 124         result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
 
 127                 wusbhc->mmcie[handle] = wuie;
 
 129         mutex_unlock(&wusbhc->mmcie_mutex);
 
 132 EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
 
 135  * Remove an MMC IE previously added with wusbhc_mmcie_set()
 
 137  * @wuie        Pointer used to add the WUIE
 
 139 void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
 
 142         unsigned handle, itr;
 
 144         mutex_lock(&wusbhc->mmcie_mutex);
 
 145         for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
 
 146                 if (wusbhc->mmcie[itr] == wuie) {
 
 151         mutex_unlock(&wusbhc->mmcie_mutex);
 
 155         result = (wusbhc->mmcie_rm)(wusbhc, handle);
 
 157                 wusbhc->mmcie[itr] = NULL;
 
 158         mutex_unlock(&wusbhc->mmcie_mutex);
 
 160 EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
 
 162 static int wusbhc_mmc_start(struct wusbhc *wusbhc)
 
 166         mutex_lock(&wusbhc->mutex);
 
 167         ret = wusbhc->start(wusbhc);
 
 170         mutex_unlock(&wusbhc->mutex);
 
 175 static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
 
 177         mutex_lock(&wusbhc->mutex);
 
 179         wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
 
 180         mutex_unlock(&wusbhc->mutex);
 
 184  * wusbhc_start - start transmitting MMCs and accepting connections
 
 185  * @wusbhc: the HC to start
 
 187  * Establishes a cluster reservation, enables device connections, and
 
 188  * starts MMCs with appropriate DNTS parameters.
 
 190 int wusbhc_start(struct wusbhc *wusbhc)
 
 193         struct device *dev = wusbhc->dev;
 
 195         WARN_ON(wusbhc->wuie_host_info != NULL);
 
 197         result = wusbhc_rsv_establish(wusbhc);
 
 199                 dev_err(dev, "cannot establish cluster reservation: %d\n",
 
 201                 goto error_rsv_establish;
 
 204         result = wusbhc_devconnect_start(wusbhc);
 
 206                 dev_err(dev, "error enabling device connections: %d\n", result);
 
 207                 goto error_devconnect_start;
 
 210         result = wusbhc_sec_start(wusbhc);
 
 212                 dev_err(dev, "error starting security in the HC: %d\n", result);
 
 213                 goto error_sec_start;
 
 215         /* FIXME: the choice of the DNTS parameters is somewhat
 
 217         result = wusbhc->set_num_dnts(wusbhc, 0, 15);
 
 219                 dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
 
 220                 goto error_set_num_dnts;
 
 222         result = wusbhc_mmc_start(wusbhc);
 
 224                 dev_err(dev, "error starting wusbch: %d\n", result);
 
 225                 goto error_wusbhc_start;
 
 231         wusbhc_sec_stop(wusbhc);
 
 234         wusbhc_devconnect_stop(wusbhc);
 
 235 error_devconnect_start:
 
 236         wusbhc_rsv_terminate(wusbhc);
 
 242  * wusbhc_stop - stop transmitting MMCs
 
 243  * @wusbhc: the HC to stop
 
 245  * Stops the WUSB channel and removes the cluster reservation.
 
 247 void wusbhc_stop(struct wusbhc *wusbhc)
 
 249         wusbhc_mmc_stop(wusbhc);
 
 250         wusbhc_sec_stop(wusbhc);
 
 251         wusbhc_devconnect_stop(wusbhc);
 
 252         wusbhc_rsv_terminate(wusbhc);
 
 256  * Set/reset/update a new CHID
 
 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
 
 262 int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
 
 266         if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0)
 
 269         mutex_lock(&wusbhc->mutex);
 
 271                 if (wusbhc->active) {
 
 272                         mutex_unlock(&wusbhc->mutex);
 
 275                 wusbhc->chid = *chid;
 
 277         mutex_unlock(&wusbhc->mutex);
 
 280                 result = uwb_radio_start(&wusbhc->pal);
 
 282                 uwb_radio_stop(&wusbhc->pal);
 
 285 EXPORT_SYMBOL_GPL(wusbhc_chid_set);