1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2014 Redpine Signals Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
5*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
6*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*4882a593Smuzhiyun * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*4882a593Smuzhiyun * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*4882a593Smuzhiyun * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/firmware.h>
21*4882a593Smuzhiyun #include <net/rsi_91x.h>
22*4882a593Smuzhiyun #include "rsi_mgmt.h"
23*4882a593Smuzhiyun #include "rsi_common.h"
24*4882a593Smuzhiyun #include "rsi_coex.h"
25*4882a593Smuzhiyun #include "rsi_hal.h"
26*4882a593Smuzhiyun #include "rsi_usb.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun u32 rsi_zone_enabled = /* INFO_ZONE |
29*4882a593Smuzhiyun INIT_ZONE |
30*4882a593Smuzhiyun MGMT_TX_ZONE |
31*4882a593Smuzhiyun MGMT_RX_ZONE |
32*4882a593Smuzhiyun DATA_TX_ZONE |
33*4882a593Smuzhiyun DATA_RX_ZONE |
34*4882a593Smuzhiyun FSM_ZONE |
35*4882a593Smuzhiyun ISR_ZONE | */
36*4882a593Smuzhiyun ERR_ZONE |
37*4882a593Smuzhiyun 0;
38*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rsi_zone_enabled);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
41*4882a593Smuzhiyun static struct rsi_proto_ops g_proto_ops = {
42*4882a593Smuzhiyun .coex_send_pkt = rsi_coex_send_pkt,
43*4882a593Smuzhiyun .get_host_intf = rsi_get_host_intf,
44*4882a593Smuzhiyun .set_bt_context = rsi_set_bt_context,
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun #endif
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /**
49*4882a593Smuzhiyun * rsi_dbg() - This function outputs informational messages.
50*4882a593Smuzhiyun * @zone: Zone of interest for output message.
51*4882a593Smuzhiyun * @fmt: printf-style format for output message.
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun * Return: none
54*4882a593Smuzhiyun */
rsi_dbg(u32 zone,const char * fmt,...)55*4882a593Smuzhiyun void rsi_dbg(u32 zone, const char *fmt, ...)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun struct va_format vaf;
58*4882a593Smuzhiyun va_list args;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun va_start(args, fmt);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun vaf.fmt = fmt;
63*4882a593Smuzhiyun vaf.va = &args;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (zone & rsi_zone_enabled)
66*4882a593Smuzhiyun pr_info("%pV", &vaf);
67*4882a593Smuzhiyun va_end(args);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rsi_dbg);
70*4882a593Smuzhiyun
opmode_str(int oper_mode)71*4882a593Smuzhiyun static char *opmode_str(int oper_mode)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun switch (oper_mode) {
74*4882a593Smuzhiyun case DEV_OPMODE_WIFI_ALONE:
75*4882a593Smuzhiyun return "Wi-Fi alone";
76*4882a593Smuzhiyun case DEV_OPMODE_BT_ALONE:
77*4882a593Smuzhiyun return "BT EDR alone";
78*4882a593Smuzhiyun case DEV_OPMODE_BT_LE_ALONE:
79*4882a593Smuzhiyun return "BT LE alone";
80*4882a593Smuzhiyun case DEV_OPMODE_BT_DUAL:
81*4882a593Smuzhiyun return "BT Dual";
82*4882a593Smuzhiyun case DEV_OPMODE_STA_BT:
83*4882a593Smuzhiyun return "Wi-Fi STA + BT EDR";
84*4882a593Smuzhiyun case DEV_OPMODE_STA_BT_LE:
85*4882a593Smuzhiyun return "Wi-Fi STA + BT LE";
86*4882a593Smuzhiyun case DEV_OPMODE_STA_BT_DUAL:
87*4882a593Smuzhiyun return "Wi-Fi STA + BT DUAL";
88*4882a593Smuzhiyun case DEV_OPMODE_AP_BT:
89*4882a593Smuzhiyun return "Wi-Fi AP + BT EDR";
90*4882a593Smuzhiyun case DEV_OPMODE_AP_BT_DUAL:
91*4882a593Smuzhiyun return "Wi-Fi AP + BT DUAL";
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun return "Unknown";
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
rsi_print_version(struct rsi_common * common)97*4882a593Smuzhiyun void rsi_print_version(struct rsi_common *common)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "================================================\n");
100*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "================ RSI Version Info ==============\n");
101*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "================================================\n");
102*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "FW Version\t: %d.%d.%d\n",
103*4882a593Smuzhiyun common->lmac_ver.major, common->lmac_ver.minor,
104*4882a593Smuzhiyun common->lmac_ver.release_num);
105*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Operating mode\t: %d [%s]",
106*4882a593Smuzhiyun common->oper_mode, opmode_str(common->oper_mode));
107*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Firmware file\t: %s", common->priv->fw_file_name);
108*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "================================================\n");
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /**
112*4882a593Smuzhiyun * rsi_prepare_skb() - This function prepares the skb.
113*4882a593Smuzhiyun * @common: Pointer to the driver private structure.
114*4882a593Smuzhiyun * @buffer: Pointer to the packet data.
115*4882a593Smuzhiyun * @pkt_len: Length of the packet.
116*4882a593Smuzhiyun * @extended_desc: Extended descriptor.
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun * Return: Successfully skb.
119*4882a593Smuzhiyun */
rsi_prepare_skb(struct rsi_common * common,u8 * buffer,u32 pkt_len,u8 extended_desc)120*4882a593Smuzhiyun static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
121*4882a593Smuzhiyun u8 *buffer,
122*4882a593Smuzhiyun u32 pkt_len,
123*4882a593Smuzhiyun u8 extended_desc)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct sk_buff *skb = NULL;
126*4882a593Smuzhiyun u8 payload_offset;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (WARN(!pkt_len, "%s: Dummy pkt received", __func__))
129*4882a593Smuzhiyun return NULL;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) {
132*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n",
133*4882a593Smuzhiyun __func__, pkt_len);
134*4882a593Smuzhiyun pkt_len = RSI_RCV_BUFFER_LEN * 4;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun pkt_len -= extended_desc;
138*4882a593Smuzhiyun skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ);
139*4882a593Smuzhiyun if (skb == NULL)
140*4882a593Smuzhiyun return NULL;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun payload_offset = (extended_desc + FRAME_DESC_SZ);
143*4882a593Smuzhiyun skb_put(skb, pkt_len);
144*4882a593Smuzhiyun memcpy((skb->data), (buffer + payload_offset), skb->len);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun return skb;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /**
150*4882a593Smuzhiyun * rsi_read_pkt() - This function reads frames from the card.
151*4882a593Smuzhiyun * @common: Pointer to the driver private structure.
152*4882a593Smuzhiyun * @rx_pkt: Received pkt.
153*4882a593Smuzhiyun * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
154*4882a593Smuzhiyun *
155*4882a593Smuzhiyun * Return: 0 on success, -1 on failure.
156*4882a593Smuzhiyun */
rsi_read_pkt(struct rsi_common * common,u8 * rx_pkt,s32 rcv_pkt_len)157*4882a593Smuzhiyun int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun u8 *frame_desc = NULL, extended_desc = 0;
160*4882a593Smuzhiyun u32 index, length = 0, queueno = 0;
161*4882a593Smuzhiyun u16 actual_length = 0, offset;
162*4882a593Smuzhiyun struct sk_buff *skb = NULL;
163*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
164*4882a593Smuzhiyun u8 bt_pkt_type;
165*4882a593Smuzhiyun #endif
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun index = 0;
168*4882a593Smuzhiyun do {
169*4882a593Smuzhiyun frame_desc = &rx_pkt[index];
170*4882a593Smuzhiyun actual_length = *(u16 *)&frame_desc[0];
171*4882a593Smuzhiyun offset = *(u16 *)&frame_desc[2];
172*4882a593Smuzhiyun if (!rcv_pkt_len && offset >
173*4882a593Smuzhiyun RSI_MAX_RX_USB_PKT_SIZE - FRAME_DESC_SZ)
174*4882a593Smuzhiyun goto fail;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun queueno = rsi_get_queueno(frame_desc, offset);
177*4882a593Smuzhiyun length = rsi_get_length(frame_desc, offset);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* Extended descriptor is valid for WLAN queues only */
180*4882a593Smuzhiyun if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
181*4882a593Smuzhiyun extended_desc = rsi_get_extended_desc(frame_desc,
182*4882a593Smuzhiyun offset);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun switch (queueno) {
185*4882a593Smuzhiyun case RSI_COEX_Q:
186*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
187*4882a593Smuzhiyun if (common->coex_mode > 1)
188*4882a593Smuzhiyun rsi_coex_recv_pkt(common, frame_desc + offset);
189*4882a593Smuzhiyun else
190*4882a593Smuzhiyun #endif
191*4882a593Smuzhiyun rsi_mgmt_pkt_recv(common,
192*4882a593Smuzhiyun (frame_desc + offset));
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun case RSI_WIFI_DATA_Q:
196*4882a593Smuzhiyun skb = rsi_prepare_skb(common,
197*4882a593Smuzhiyun (frame_desc + offset),
198*4882a593Smuzhiyun length,
199*4882a593Smuzhiyun extended_desc);
200*4882a593Smuzhiyun if (skb == NULL)
201*4882a593Smuzhiyun goto fail;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun rsi_indicate_pkt_to_os(common, skb);
204*4882a593Smuzhiyun break;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun case RSI_WIFI_MGMT_Q:
207*4882a593Smuzhiyun rsi_mgmt_pkt_recv(common, (frame_desc + offset));
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
211*4882a593Smuzhiyun case RSI_BT_MGMT_Q:
212*4882a593Smuzhiyun case RSI_BT_DATA_Q:
213*4882a593Smuzhiyun #define BT_RX_PKT_TYPE_OFST 14
214*4882a593Smuzhiyun #define BT_CARD_READY_IND 0x89
215*4882a593Smuzhiyun bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
216*4882a593Smuzhiyun if (bt_pkt_type == BT_CARD_READY_IND) {
217*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
218*4882a593Smuzhiyun if (common->fsm_state == FSM_MAC_INIT_DONE)
219*4882a593Smuzhiyun rsi_attach_bt(common);
220*4882a593Smuzhiyun else
221*4882a593Smuzhiyun common->bt_defer_attach = true;
222*4882a593Smuzhiyun } else {
223*4882a593Smuzhiyun if (common->bt_adapter)
224*4882a593Smuzhiyun rsi_bt_ops.recv_pkt(common->bt_adapter,
225*4882a593Smuzhiyun frame_desc + offset);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun break;
228*4882a593Smuzhiyun #endif
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun default:
231*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
232*4882a593Smuzhiyun __func__, queueno);
233*4882a593Smuzhiyun goto fail;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun index += actual_length;
237*4882a593Smuzhiyun rcv_pkt_len -= actual_length;
238*4882a593Smuzhiyun } while (rcv_pkt_len > 0);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun return 0;
241*4882a593Smuzhiyun fail:
242*4882a593Smuzhiyun return -EINVAL;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rsi_read_pkt);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /**
247*4882a593Smuzhiyun * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
248*4882a593Smuzhiyun * packets to the device.
249*4882a593Smuzhiyun * @common: Pointer to the driver private structure.
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun * Return: None.
252*4882a593Smuzhiyun */
rsi_tx_scheduler_thread(struct rsi_common * common)253*4882a593Smuzhiyun static void rsi_tx_scheduler_thread(struct rsi_common *common)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun struct rsi_hw *adapter = common->priv;
256*4882a593Smuzhiyun u32 timeout = EVENT_WAIT_FOREVER;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun do {
259*4882a593Smuzhiyun if (adapter->determine_event_timeout)
260*4882a593Smuzhiyun timeout = adapter->determine_event_timeout(adapter);
261*4882a593Smuzhiyun rsi_wait_event(&common->tx_thread.event, timeout);
262*4882a593Smuzhiyun rsi_reset_event(&common->tx_thread.event);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (common->init_done)
265*4882a593Smuzhiyun rsi_core_qos_processor(common);
266*4882a593Smuzhiyun } while (atomic_read(&common->tx_thread.thread_done) == 0);
267*4882a593Smuzhiyun complete_and_exit(&common->tx_thread.completion, 0);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
rsi_get_host_intf(void * priv)271*4882a593Smuzhiyun enum rsi_host_intf rsi_get_host_intf(void *priv)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun struct rsi_common *common = (struct rsi_common *)priv;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun return common->priv->rsi_host_intf;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
rsi_set_bt_context(void * priv,void * bt_context)278*4882a593Smuzhiyun void rsi_set_bt_context(void *priv, void *bt_context)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun struct rsi_common *common = (struct rsi_common *)priv;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun common->bt_adapter = bt_context;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun #endif
285*4882a593Smuzhiyun
rsi_attach_bt(struct rsi_common * common)286*4882a593Smuzhiyun void rsi_attach_bt(struct rsi_common *common)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
289*4882a593Smuzhiyun if (rsi_bt_ops.attach(common, &g_proto_ops))
290*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
291*4882a593Smuzhiyun "Failed to attach BT module\n");
292*4882a593Smuzhiyun #endif
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /**
296*4882a593Smuzhiyun * rsi_91x_init() - This function initializes os interface operations.
297*4882a593Smuzhiyun * @oper_mode: One of DEV_OPMODE_*.
298*4882a593Smuzhiyun *
299*4882a593Smuzhiyun * Return: Pointer to the adapter structure on success, NULL on failure .
300*4882a593Smuzhiyun */
rsi_91x_init(u16 oper_mode)301*4882a593Smuzhiyun struct rsi_hw *rsi_91x_init(u16 oper_mode)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun struct rsi_hw *adapter = NULL;
304*4882a593Smuzhiyun struct rsi_common *common = NULL;
305*4882a593Smuzhiyun u8 ii = 0;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
308*4882a593Smuzhiyun if (!adapter)
309*4882a593Smuzhiyun return NULL;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
312*4882a593Smuzhiyun if (adapter->priv == NULL) {
313*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
314*4882a593Smuzhiyun __func__);
315*4882a593Smuzhiyun kfree(adapter);
316*4882a593Smuzhiyun return NULL;
317*4882a593Smuzhiyun } else {
318*4882a593Smuzhiyun common = adapter->priv;
319*4882a593Smuzhiyun common->priv = adapter;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
323*4882a593Smuzhiyun skb_queue_head_init(&common->tx_queue[ii]);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun rsi_init_event(&common->tx_thread.event);
326*4882a593Smuzhiyun mutex_init(&common->mutex);
327*4882a593Smuzhiyun mutex_init(&common->tx_lock);
328*4882a593Smuzhiyun mutex_init(&common->rx_lock);
329*4882a593Smuzhiyun mutex_init(&common->tx_bus_mutex);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (rsi_create_kthread(common,
332*4882a593Smuzhiyun &common->tx_thread,
333*4882a593Smuzhiyun rsi_tx_scheduler_thread,
334*4882a593Smuzhiyun "Tx-Thread")) {
335*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
336*4882a593Smuzhiyun goto err;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun rsi_default_ps_params(adapter);
340*4882a593Smuzhiyun init_bgscan_params(common);
341*4882a593Smuzhiyun spin_lock_init(&adapter->ps_lock);
342*4882a593Smuzhiyun timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
343*4882a593Smuzhiyun init_completion(&common->wlan_init_completion);
344*4882a593Smuzhiyun adapter->device_model = RSI_DEV_9113;
345*4882a593Smuzhiyun common->oper_mode = oper_mode;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* Determine coex mode */
348*4882a593Smuzhiyun switch (common->oper_mode) {
349*4882a593Smuzhiyun case DEV_OPMODE_STA_BT_DUAL:
350*4882a593Smuzhiyun case DEV_OPMODE_STA_BT:
351*4882a593Smuzhiyun case DEV_OPMODE_STA_BT_LE:
352*4882a593Smuzhiyun case DEV_OPMODE_BT_ALONE:
353*4882a593Smuzhiyun case DEV_OPMODE_BT_LE_ALONE:
354*4882a593Smuzhiyun case DEV_OPMODE_BT_DUAL:
355*4882a593Smuzhiyun common->coex_mode = 2;
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun case DEV_OPMODE_AP_BT_DUAL:
358*4882a593Smuzhiyun case DEV_OPMODE_AP_BT:
359*4882a593Smuzhiyun common->coex_mode = 4;
360*4882a593Smuzhiyun break;
361*4882a593Smuzhiyun case DEV_OPMODE_WIFI_ALONE:
362*4882a593Smuzhiyun common->coex_mode = 1;
363*4882a593Smuzhiyun break;
364*4882a593Smuzhiyun default:
365*4882a593Smuzhiyun common->oper_mode = 1;
366*4882a593Smuzhiyun common->coex_mode = 1;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
369*4882a593Smuzhiyun __func__, common->oper_mode, common->coex_mode);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun adapter->device_model = RSI_DEV_9113;
372*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
373*4882a593Smuzhiyun if (common->coex_mode > 1) {
374*4882a593Smuzhiyun if (rsi_coex_attach(common)) {
375*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
376*4882a593Smuzhiyun rsi_kill_thread(&common->tx_thread);
377*4882a593Smuzhiyun goto err;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun #endif
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun common->init_done = true;
383*4882a593Smuzhiyun return adapter;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun err:
386*4882a593Smuzhiyun kfree(common);
387*4882a593Smuzhiyun kfree(adapter);
388*4882a593Smuzhiyun return NULL;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rsi_91x_init);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /**
393*4882a593Smuzhiyun * rsi_91x_deinit() - This function de-intializes os intf operations.
394*4882a593Smuzhiyun * @adapter: Pointer to the adapter structure.
395*4882a593Smuzhiyun *
396*4882a593Smuzhiyun * Return: None.
397*4882a593Smuzhiyun */
rsi_91x_deinit(struct rsi_hw * adapter)398*4882a593Smuzhiyun void rsi_91x_deinit(struct rsi_hw *adapter)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun struct rsi_common *common = adapter->priv;
401*4882a593Smuzhiyun u8 ii;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun rsi_kill_thread(&common->tx_thread);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
408*4882a593Smuzhiyun skb_queue_purge(&common->tx_queue[ii]);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun #ifdef CONFIG_RSI_COEX
411*4882a593Smuzhiyun if (common->coex_mode > 1) {
412*4882a593Smuzhiyun if (common->bt_adapter) {
413*4882a593Smuzhiyun rsi_bt_ops.detach(common->bt_adapter);
414*4882a593Smuzhiyun common->bt_adapter = NULL;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun rsi_coex_detach(common);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun #endif
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun common->init_done = false;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun kfree(common);
423*4882a593Smuzhiyun kfree(adapter->rsi_dev);
424*4882a593Smuzhiyun kfree(adapter);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rsi_91x_deinit);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /**
429*4882a593Smuzhiyun * rsi_91x_hal_module_init() - This function is invoked when the module is
430*4882a593Smuzhiyun * loaded into the kernel.
431*4882a593Smuzhiyun * It registers the client driver.
432*4882a593Smuzhiyun * @void: Void.
433*4882a593Smuzhiyun *
434*4882a593Smuzhiyun * Return: 0 on success, -1 on failure.
435*4882a593Smuzhiyun */
rsi_91x_hal_module_init(void)436*4882a593Smuzhiyun static int rsi_91x_hal_module_init(void)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /**
443*4882a593Smuzhiyun * rsi_91x_hal_module_exit() - This function is called at the time of
444*4882a593Smuzhiyun * removing/unloading the module.
445*4882a593Smuzhiyun * It unregisters the client driver.
446*4882a593Smuzhiyun * @void: Void.
447*4882a593Smuzhiyun *
448*4882a593Smuzhiyun * Return: None.
449*4882a593Smuzhiyun */
rsi_91x_hal_module_exit(void)450*4882a593Smuzhiyun static void rsi_91x_hal_module_exit(void)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun module_init(rsi_91x_hal_module_init);
456*4882a593Smuzhiyun module_exit(rsi_91x_hal_module_exit);
457*4882a593Smuzhiyun MODULE_AUTHOR("Redpine Signals Inc");
458*4882a593Smuzhiyun MODULE_DESCRIPTION("Station driver for RSI 91x devices");
459*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("RSI-91x");
460*4882a593Smuzhiyun MODULE_VERSION("0.1");
461*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
462