linux/drivers/net/wireless/rsi/rsi_91x_main.c
<<
>>
Prefs
   1/**
   2 * Copyright (c) 2014 Redpine Signals Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/module.h>
  20#include <linux/firmware.h>
  21#include "rsi_mgmt.h"
  22#include "rsi_common.h"
  23
  24u32 rsi_zone_enabled = /* INFO_ZONE |
  25                        INIT_ZONE |
  26                        MGMT_TX_ZONE |
  27                        MGMT_RX_ZONE |
  28                        DATA_TX_ZONE |
  29                        DATA_RX_ZONE |
  30                        FSM_ZONE |
  31                        ISR_ZONE | */
  32                        ERR_ZONE |
  33                        0;
  34EXPORT_SYMBOL_GPL(rsi_zone_enabled);
  35
  36/**
  37 * rsi_dbg() - This function outputs informational messages.
  38 * @zone: Zone of interest for output message.
  39 * @fmt: printf-style format for output message.
  40 *
  41 * Return: none
  42 */
  43void rsi_dbg(u32 zone, const char *fmt, ...)
  44{
  45        struct va_format vaf;
  46        va_list args;
  47
  48        va_start(args, fmt);
  49
  50        vaf.fmt = fmt;
  51        vaf.va = &args;
  52
  53        if (zone & rsi_zone_enabled)
  54                pr_info("%pV", &vaf);
  55        va_end(args);
  56}
  57EXPORT_SYMBOL_GPL(rsi_dbg);
  58
  59/**
  60 * rsi_prepare_skb() - This function prepares the skb.
  61 * @common: Pointer to the driver private structure.
  62 * @buffer: Pointer to the packet data.
  63 * @pkt_len: Length of the packet.
  64 * @extended_desc: Extended descriptor.
  65 *
  66 * Return: Successfully skb.
  67 */
  68static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
  69                                       u8 *buffer,
  70                                       u32 pkt_len,
  71                                       u8 extended_desc)
  72{
  73        struct ieee80211_tx_info *info;
  74        struct skb_info *rx_params;
  75        struct sk_buff *skb = NULL;
  76        u8 payload_offset;
  77
  78        if (WARN(!pkt_len, "%s: Dummy pkt received", __func__))
  79                return NULL;
  80
  81        if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) {
  82                rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n",
  83                        __func__, pkt_len);
  84                pkt_len = RSI_RCV_BUFFER_LEN * 4;
  85        }
  86
  87        pkt_len -= extended_desc;
  88        skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ);
  89        if (skb == NULL)
  90                return NULL;
  91
  92        payload_offset = (extended_desc + FRAME_DESC_SZ);
  93        skb_put(skb, pkt_len);
  94        memcpy((skb->data), (buffer + payload_offset), skb->len);
  95
  96        info = IEEE80211_SKB_CB(skb);
  97        rx_params = (struct skb_info *)info->driver_data;
  98        rx_params->rssi = rsi_get_rssi(buffer);
  99        rx_params->channel = rsi_get_connected_channel(common->priv);
 100
 101        return skb;
 102}
 103
 104/**
 105 * rsi_read_pkt() - This function reads frames from the card.
 106 * @common: Pointer to the driver private structure.
 107 * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
 108 *
 109 * Return: 0 on success, -1 on failure.
 110 */
 111int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
 112{
 113        u8 *frame_desc = NULL, extended_desc = 0;
 114        u32 index, length = 0, queueno = 0;
 115        u16 actual_length = 0, offset;
 116        struct sk_buff *skb = NULL;
 117
 118        index = 0;
 119        do {
 120                frame_desc = &common->rx_data_pkt[index];
 121                actual_length = *(u16 *)&frame_desc[0];
 122                offset = *(u16 *)&frame_desc[2];
 123
 124                queueno = rsi_get_queueno(frame_desc, offset);
 125                length = rsi_get_length(frame_desc, offset);
 126                extended_desc = rsi_get_extended_desc(frame_desc, offset);
 127
 128                switch (queueno) {
 129                case RSI_WIFI_DATA_Q:
 130                        skb = rsi_prepare_skb(common,
 131                                              (frame_desc + offset),
 132                                              length,
 133                                              extended_desc);
 134                        if (skb == NULL)
 135                                goto fail;
 136
 137                        rsi_indicate_pkt_to_os(common, skb);
 138                        break;
 139
 140                case RSI_WIFI_MGMT_Q:
 141                        rsi_mgmt_pkt_recv(common, (frame_desc + offset));
 142                        break;
 143
 144                default:
 145                        rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
 146                                __func__,   queueno);
 147                        goto fail;
 148                }
 149
 150                index  += actual_length;
 151                rcv_pkt_len -= actual_length;
 152        } while (rcv_pkt_len > 0);
 153
 154        return 0;
 155fail:
 156        return -EINVAL;
 157}
 158EXPORT_SYMBOL_GPL(rsi_read_pkt);
 159
 160/**
 161 * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
 162 *                             packets to the device.
 163 * @common: Pointer to the driver private structure.
 164 *
 165 * Return: None.
 166 */
 167static void rsi_tx_scheduler_thread(struct rsi_common *common)
 168{
 169        struct rsi_hw *adapter = common->priv;
 170        u32 timeout = EVENT_WAIT_FOREVER;
 171
 172        do {
 173                if (adapter->determine_event_timeout)
 174                        timeout = adapter->determine_event_timeout(adapter);
 175                rsi_wait_event(&common->tx_thread.event, timeout);
 176                rsi_reset_event(&common->tx_thread.event);
 177
 178                if (common->init_done)
 179                        rsi_core_qos_processor(common);
 180        } while (atomic_read(&common->tx_thread.thread_done) == 0);
 181        complete_and_exit(&common->tx_thread.completion, 0);
 182}
 183
 184/**
 185 * rsi_91x_init() - This function initializes os interface operations.
 186 * @void: Void.
 187 *
 188 * Return: Pointer to the adapter structure on success, NULL on failure .
 189 */
 190struct rsi_hw *rsi_91x_init(void)
 191{
 192        struct rsi_hw *adapter = NULL;
 193        struct rsi_common *common = NULL;
 194        u8 ii = 0;
 195
 196        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
 197        if (!adapter)
 198                return NULL;
 199
 200        adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
 201        if (adapter->priv == NULL) {
 202                rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
 203                        __func__);
 204                kfree(adapter);
 205                return NULL;
 206        } else {
 207                common = adapter->priv;
 208                common->priv = adapter;
 209        }
 210
 211        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 212                skb_queue_head_init(&common->tx_queue[ii]);
 213
 214        rsi_init_event(&common->tx_thread.event);
 215        mutex_init(&common->mutex);
 216        mutex_init(&common->tx_rxlock);
 217
 218        if (rsi_create_kthread(common,
 219                               &common->tx_thread,
 220                               rsi_tx_scheduler_thread,
 221                               "Tx-Thread")) {
 222                rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
 223                goto err;
 224        }
 225
 226        common->init_done = true;
 227        return adapter;
 228
 229err:
 230        kfree(common);
 231        kfree(adapter);
 232        return NULL;
 233}
 234EXPORT_SYMBOL_GPL(rsi_91x_init);
 235
 236/**
 237 * rsi_91x_deinit() - This function de-intializes os intf operations.
 238 * @adapter: Pointer to the adapter structure.
 239 *
 240 * Return: None.
 241 */
 242void rsi_91x_deinit(struct rsi_hw *adapter)
 243{
 244        struct rsi_common *common = adapter->priv;
 245        u8 ii;
 246
 247        rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
 248
 249        rsi_kill_thread(&common->tx_thread);
 250
 251        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 252                skb_queue_purge(&common->tx_queue[ii]);
 253
 254        common->init_done = false;
 255
 256        kfree(common);
 257        kfree(adapter->rsi_dev);
 258        kfree(adapter);
 259}
 260EXPORT_SYMBOL_GPL(rsi_91x_deinit);
 261
 262/**
 263 * rsi_91x_hal_module_init() - This function is invoked when the module is
 264 *                             loaded into the kernel.
 265 *                             It registers the client driver.
 266 * @void: Void.
 267 *
 268 * Return: 0 on success, -1 on failure.
 269 */
 270static int rsi_91x_hal_module_init(void)
 271{
 272        rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
 273        return 0;
 274}
 275
 276/**
 277 * rsi_91x_hal_module_exit() - This function is called at the time of
 278 *                             removing/unloading the module.
 279 *                             It unregisters the client driver.
 280 * @void: Void.
 281 *
 282 * Return: None.
 283 */
 284static void rsi_91x_hal_module_exit(void)
 285{
 286        rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__);
 287}
 288
 289module_init(rsi_91x_hal_module_init);
 290module_exit(rsi_91x_hal_module_exit);
 291MODULE_AUTHOR("Redpine Signals Inc");
 292MODULE_DESCRIPTION("Station driver for RSI 91x devices");
 293MODULE_SUPPORTED_DEVICE("RSI-91x");
 294MODULE_VERSION("0.1");
 295MODULE_LICENSE("Dual BSD/GPL");
 296