blob: 02f5e0c90f9ae1513804acfb62819c7900452a98 [file] [log] [blame]
Larry Fingera2c60d42013-08-21 22:33:58 -05001/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 *
19 ******************************************************************************/
20
21
22#define _OSDEP_SERVICE_C_
23
24#include <osdep_service.h>
25#include <drv_types.h>
26#include <recv_osdep.h>
27#include <linux/vmalloc.h>
28#include <rtw_ioctl_set.h>
29
30/*
31* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE
32* @return: one of RTW_STATUS_CODE
33*/
34inline int RTW_STATUS_CODE(int error_code)
35{
36 if (error_code >= 0)
37 return _SUCCESS;
38 return _FAIL;
39}
40
41u32 rtw_atoi(u8 *s)
42{
43 int num = 0, flag = 0;
44 int i;
45 for (i = 0; i <= strlen(s); i++) {
46 if (s[i] >= '0' && s[i] <= '9')
47 num = num * 10 + s[i] - '0';
48 else if (s[0] == '-' && i == 0)
49 flag = 1;
50 else
51 break;
52 }
53 if (flag == 1)
54 num = num * -1;
Teodora Baluta1f9d82d2013-11-08 00:13:46 +020055 return num;
Larry Fingera2c60d42013-08-21 22:33:58 -050056}
57
Larry Fingera2c60d42013-08-21 22:33:58 -050058inline void _rtw_vmfree(u8 *pbuf, u32 sz)
59{
60 vfree(pbuf);
61}
62
63u8 *_rtw_malloc(u32 sz)
64{
65 u8 *pbuf = NULL;
66
67 pbuf = kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
68 return pbuf;
69}
70
71u8 *_rtw_zmalloc(u32 sz)
72{
73 u8 *pbuf = _rtw_malloc(sz);
74
75 if (pbuf != NULL)
76 memset(pbuf, 0, sz);
77 return pbuf;
78}
79
80void *rtw_malloc2d(int h, int w, int size)
81{
82 int j;
83
84 void **a = (void **)rtw_zmalloc(h*sizeof(void *) + h*w*size);
85 if (a == NULL) {
86 pr_info("%s: alloc memory fail!\n", __func__);
87 return NULL;
88 }
89
90 for (j = 0; j < h; j++)
91 a[j] = ((char *)(a+h)) + j*w*size;
92
93 return a;
94}
95
96void rtw_mfree2d(void *pbuf, int h, int w, int size)
97{
98 kfree(pbuf);
99}
100
101int _rtw_memcmp(void *dst, void *src, u32 sz)
102{
103/* under Linux/GNU/GLibc, the return value of memcmp for two same
104 * mem. chunk is 0 */
105 if (!(memcmp(dst, src, sz)))
106 return true;
107 else
108 return false;
109}
110
111void _rtw_memset(void *pbuf, int c, u32 sz)
112{
113 memset(pbuf, c, sz);
114}
115
116void _rtw_init_listhead(struct list_head *list)
117{
118 INIT_LIST_HEAD(list);
119}
120
121/*
122For the following list_xxx operations,
123caller must guarantee the atomic context.
124Otherwise, there will be racing condition.
125*/
126u32 rtw_is_list_empty(struct list_head *phead)
127{
128 if (list_empty(phead))
129 return true;
130 else
131 return false;
132}
133
134void rtw_list_insert_head(struct list_head *plist, struct list_head *phead)
135{
136 list_add(plist, phead);
137}
138
139void rtw_list_insert_tail(struct list_head *plist, struct list_head *phead)
140{
141 list_add_tail(plist, phead);
142}
143
144/*
145Caller must check if the list is empty before calling rtw_list_delete
146*/
147
Larry Fingera2c60d42013-08-21 22:33:58 -0500148u32 _rtw_down_sema(struct semaphore *sema)
149{
150 if (down_interruptible(sema))
151 return _FAIL;
152 else
153 return _SUCCESS;
154}
155
Larry Fingera2c60d42013-08-21 22:33:58 -0500156void _rtw_init_queue(struct __queue *pqueue)
157{
158 _rtw_init_listhead(&(pqueue->queue));
Larry Fingerf214e522013-12-19 22:38:38 -0600159 spin_lock_init(&(pqueue->lock));
Larry Fingera2c60d42013-08-21 22:33:58 -0500160}
161
162u32 _rtw_queue_empty(struct __queue *pqueue)
163{
164 return rtw_is_list_empty(&(pqueue->queue));
165}
166
167u32 rtw_end_of_queue_search(struct list_head *head, struct list_head *plist)
168{
169 if (head == plist)
170 return true;
171 else
172 return false;
173}
174
Larry Fingera2c60d42013-08-21 22:33:58 -0500175inline u32 rtw_systime_to_ms(u32 systime)
176{
177 return systime * 1000 / HZ;
178}
179
180inline u32 rtw_ms_to_systime(u32 ms)
181{
182 return ms * HZ / 1000;
183}
184
Larry Fingerc01fb492013-12-19 22:38:40 -0600185/* the input parameter start must be in jiffies */
Larry Fingera2c60d42013-08-21 22:33:58 -0500186inline s32 rtw_get_passing_time_ms(u32 start)
187{
188 return rtw_systime_to_ms(jiffies-start);
189}
190
191inline s32 rtw_get_time_interval_ms(u32 start, u32 end)
192{
193 return rtw_systime_to_ms(end-start);
194}
195
196void rtw_sleep_schedulable(int ms)
197{
198 u32 delta;
199
200 delta = (ms * HZ)/1000;/* ms) */
201 if (delta == 0)
202 delta = 1;/* 1 ms */
203 set_current_state(TASK_INTERRUPTIBLE);
204 if (schedule_timeout(delta) != 0)
205 return;
206}
207
Larry Fingera2c60d42013-08-21 22:33:58 -0500208#define RTW_SUSPEND_LOCK_NAME "rtw_wifi"
209
Larry Fingera2c60d42013-08-21 22:33:58 -0500210struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv,
211 void *old_priv)
212{
213 struct net_device *pnetdev;
214 struct rtw_netdev_priv_indicator *pnpi;
215
216 pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
217 if (!pnetdev)
218 goto RETURN;
219
220 pnpi = netdev_priv(pnetdev);
221 pnpi->priv = old_priv;
222 pnpi->sizeof_priv = sizeof_priv;
223
224RETURN:
225 return pnetdev;
226}
227
228struct net_device *rtw_alloc_etherdev(int sizeof_priv)
229{
230 struct net_device *pnetdev;
231 struct rtw_netdev_priv_indicator *pnpi;
232
233 pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
234 if (!pnetdev)
235 goto RETURN;
236
237 pnpi = netdev_priv(pnetdev);
238
Larry Finger2397c6e2014-02-06 20:45:42 -0600239 pnpi->priv = vzalloc(sizeof_priv);
Larry Fingera2c60d42013-08-21 22:33:58 -0500240 if (!pnpi->priv) {
241 free_netdev(pnetdev);
242 pnetdev = NULL;
243 goto RETURN;
244 }
245
246 pnpi->sizeof_priv = sizeof_priv;
247RETURN:
248 return pnetdev;
249}
250
251void rtw_free_netdev(struct net_device *netdev)
252{
253 struct rtw_netdev_priv_indicator *pnpi;
254
255 if (!netdev)
256 goto RETURN;
257
258 pnpi = netdev_priv(netdev);
259
260 if (!pnpi->priv)
261 goto RETURN;
262
263 rtw_vmfree(pnpi->priv, pnpi->sizeof_priv);
264 free_netdev(netdev);
265
266RETURN:
267 return;
268}
269
270int rtw_change_ifname(struct adapter *padapter, const char *ifname)
271{
272 struct net_device *pnetdev;
Larry Fingerefbff732013-09-04 15:56:00 -0500273 struct net_device *cur_pnetdev;
Larry Fingera2c60d42013-08-21 22:33:58 -0500274 struct rereg_nd_name_data *rereg_priv;
275 int ret;
276
277 if (!padapter)
278 goto error;
279
Larry Fingerefbff732013-09-04 15:56:00 -0500280 cur_pnetdev = padapter->pnetdev;
Larry Fingera2c60d42013-08-21 22:33:58 -0500281 rereg_priv = &padapter->rereg_nd_name_priv;
282
283 /* free the old_pnetdev */
284 if (rereg_priv->old_pnetdev) {
285 free_netdev(rereg_priv->old_pnetdev);
286 rereg_priv->old_pnetdev = NULL;
287 }
288
289 if (!rtnl_is_locked())
290 unregister_netdev(cur_pnetdev);
291 else
292 unregister_netdevice(cur_pnetdev);
293
294 rtw_proc_remove_one(cur_pnetdev);
295
296 rereg_priv->old_pnetdev = cur_pnetdev;
297
298 pnetdev = rtw_init_netdev(padapter);
299 if (!pnetdev) {
300 ret = -1;
301 goto error;
302 }
303
304 SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter)));
305
306 rtw_init_netdev_name(pnetdev, ifname);
307
308 memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN);
309
310 if (!rtnl_is_locked())
311 ret = register_netdev(pnetdev);
312 else
313 ret = register_netdevice(pnetdev);
314 if (ret != 0) {
315 RT_TRACE(_module_hci_intfs_c_, _drv_err_,
316 ("register_netdev() failed\n"));
317 goto error;
318 }
319 rtw_proc_init_one(pnetdev);
320 return 0;
321error:
322 return -1;
323}
324
325u64 rtw_modular64(u64 x, u64 y)
326{
327 return do_div(x, y);
328}
329
330u64 rtw_division64(u64 x, u64 y)
331{
332 do_div(x, y);
333 return x;
334}
335
336void rtw_buf_free(u8 **buf, u32 *buf_len)
337{
338 *buf_len = 0;
339 kfree(*buf);
340 *buf = NULL;
341}
342
343void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len)
344{
345 u32 ori_len = 0, dup_len = 0;
346 u8 *ori = NULL;
347 u8 *dup = NULL;
348
349 if (!buf || !buf_len)
350 return;
351
352 if (!src || !src_len)
353 goto keep_ori;
354
355 /* duplicate src */
356 dup = rtw_malloc(src_len);
357 if (dup) {
358 dup_len = src_len;
359 memcpy(dup, src, dup_len);
360 }
361
362keep_ori:
363 ori = *buf;
364 ori_len = *buf_len;
365
366 /* replace buf with dup */
367 *buf_len = 0;
368 *buf = dup;
369 *buf_len = dup_len;
370
371 /* free ori */
372 kfree(ori);
373}
374
375
376/**
377 * rtw_cbuf_full - test if cbuf is full
378 * @cbuf: pointer of struct rtw_cbuf
379 *
380 * Returns: true if cbuf is full
381 */
382inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
383{
384 return (cbuf->write == cbuf->read-1) ? true : false;
385}
386
387/**
388 * rtw_cbuf_empty - test if cbuf is empty
389 * @cbuf: pointer of struct rtw_cbuf
390 *
391 * Returns: true if cbuf is empty
392 */
393inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf)
394{
395 return (cbuf->write == cbuf->read) ? true : false;
396}
397
398/**
399 * rtw_cbuf_push - push a pointer into cbuf
400 * @cbuf: pointer of struct rtw_cbuf
401 * @buf: pointer to push in
402 *
403 * Lock free operation, be careful of the use scheme
404 * Returns: true push success
405 */
406bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf)
407{
408 if (rtw_cbuf_full(cbuf))
409 return _FAIL;
410
411 if (0)
412 DBG_88E("%s on %u\n", __func__, cbuf->write);
413 cbuf->bufs[cbuf->write] = buf;
414 cbuf->write = (cbuf->write+1)%cbuf->size;
415
416 return _SUCCESS;
417}
418
419/**
420 * rtw_cbuf_pop - pop a pointer from cbuf
421 * @cbuf: pointer of struct rtw_cbuf
422 *
423 * Lock free operation, be careful of the use scheme
424 * Returns: pointer popped out
425 */
426void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
427{
428 void *buf;
429 if (rtw_cbuf_empty(cbuf))
430 return NULL;
431
432 if (0)
433 DBG_88E("%s on %u\n", __func__, cbuf->read);
434 buf = cbuf->bufs[cbuf->read];
435 cbuf->read = (cbuf->read+1)%cbuf->size;
436
437 return buf;
438}
439
440/**
Masanari Iida7efc02c2013-09-27 00:11:46 +0900441 * rtw_cbuf_alloc - allocate a rtw_cbuf with given size and do initialization
Larry Fingera2c60d42013-08-21 22:33:58 -0500442 * @size: size of pointer
443 *
444 * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure
445 */
446struct rtw_cbuf *rtw_cbuf_alloc(u32 size)
447{
448 struct rtw_cbuf *cbuf;
449
450 cbuf = (struct rtw_cbuf *)rtw_malloc(sizeof(*cbuf) +
451 sizeof(void *)*size);
452
453 if (cbuf) {
454 cbuf->write = 0;
455 cbuf->read = 0;
456 cbuf->size = size;
457 }
458 return cbuf;
459}