~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to ubuntu/ndiswrapper/ndis.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-04kado7d1u2er2rl
Tags: 3.2.0-16.25
Add new lowlatency kernel flavour

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
 
3
 *
 
4
 *  This program is free software; you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
 
8
 *
 
9
 *  This program is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 *  GNU General Public License for more details.
 
13
 *
 
14
 */
 
15
 
 
16
#include "ndis.h"
 
17
#include "iw_ndis.h"
 
18
#include "wrapndis.h"
 
19
#include "pnp.h"
 
20
#include "loader.h"
 
21
#include <linux/kernel_stat.h>
 
22
#include <asm/dma.h>
 
23
#include "ndis_exports.h"
 
24
 
 
25
#define MAX_ALLOCATED_NDIS_PACKETS TX_RING_SIZE
 
26
#define MAX_ALLOCATED_NDIS_BUFFERS TX_RING_SIZE
 
27
 
 
28
static void ndis_worker(worker_param_t dummy);
 
29
static work_struct_t ndis_work;
 
30
static struct nt_list ndis_work_list;
 
31
static spinlock_t ndis_work_list_lock;
 
32
 
 
33
workqueue_struct_t *ndis_wq;
 
34
static struct nt_thread *ndis_worker_thread;
 
35
 
 
36
static void *ndis_get_routine_address(char *name);
 
37
 
 
38
wstdcall void WIN_FUNC(NdisInitializeWrapper,4)
 
39
        (void **driver_handle, struct driver_object *driver,
 
40
         struct unicode_string *reg_path, void *unused)
 
41
{
 
42
        ENTER1("handle: %p, driver: %p", driver_handle, driver);
 
43
        *driver_handle = driver;
 
44
        EXIT1(return);
 
45
}
 
46
 
 
47
wstdcall void WIN_FUNC(NdisTerminateWrapper,2)
 
48
        (struct device_object *dev_obj, void *system_specific)
 
49
{
 
50
        EXIT1(return);
 
51
}
 
52
 
 
53
wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3)
 
54
        (struct driver_object *drv_obj, struct miniport *mp, UINT length)
 
55
{
 
56
        int min_length;
 
57
        struct wrap_driver *wrap_driver;
 
58
        struct ndis_driver *ndis_driver;
 
59
 
 
60
        min_length = ((char *)&mp->co_create_vc) - ((char *)mp);
 
61
 
 
62
        ENTER1("%p %p %d", drv_obj, mp, length);
 
63
 
 
64
        if (mp->major_version < 4) {
 
65
                ERROR("Driver is using ndis version %d which is too old.",
 
66
                      mp->major_version);
 
67
                EXIT1(return NDIS_STATUS_BAD_VERSION);
 
68
        }
 
69
 
 
70
        if (length < min_length) {
 
71
                ERROR("Characteristics length %d is too small", length);
 
72
                EXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS);
 
73
        }
 
74
 
 
75
        TRACE1("%d.%d, %d, %u", mp->major_version, mp->minor_version, length,
 
76
               (u32)sizeof(struct miniport));
 
77
        wrap_driver = IoGetDriverObjectExtension(drv_obj,
 
78
                                                 (void *)WRAP_DRIVER_CLIENT_ID);
 
79
        if (!wrap_driver) {
 
80
                ERROR("couldn't get wrap_driver");
 
81
                EXIT1(return NDIS_STATUS_RESOURCES);
 
82
        }
 
83
        if (IoAllocateDriverObjectExtension(
 
84
                    drv_obj, (void *)NDIS_DRIVER_CLIENT_ID,
 
85
                    sizeof(*ndis_driver), (void **)&ndis_driver) !=
 
86
            STATUS_SUCCESS)
 
87
                EXIT1(return NDIS_STATUS_RESOURCES);
 
88
        wrap_driver->ndis_driver = ndis_driver;
 
89
        TRACE1("driver: %p", ndis_driver);
 
90
        memcpy(&ndis_driver->mp, mp, min_t(int, sizeof(*mp), length));
 
91
 
 
92
        DBG_BLOCK(2) {
 
93
                int i;
 
94
                void **func;
 
95
                char *mp_funcs[] = {
 
96
                        "queryinfo", "reconfig", "reset", "send", "setinfo",
 
97
                        "tx_data", "return_packet", "send_packets",
 
98
                        "alloc_complete", "co_create_vc", "co_delete_vc",
 
99
                        "co_activate_vc", "co_deactivate_vc",
 
100
                        "co_send_packets", "co_request", "cancel_send_packets",
 
101
                        "pnp_event_notify", "shutdown",
 
102
                };
 
103
                func = (void **)&ndis_driver->mp.queryinfo;
 
104
                for (i = 0; i < (sizeof(mp_funcs) / sizeof(mp_funcs[0])); i++)
 
105
                        TRACE2("function '%s' is at %p", mp_funcs[i], func[i]);
 
106
        }
 
107
        EXIT1(return NDIS_STATUS_SUCCESS);
 
108
}
 
109
 
 
110
wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6)
 
111
        (struct driver_object *drv_obj, struct unicode_string *dev_name,
 
112
         struct unicode_string *link, void **funcs,
 
113
         struct device_object **dev_obj, void **dev_obj_handle)
 
114
{
 
115
        NTSTATUS status;
 
116
        struct device_object *tmp;
 
117
        int i;
 
118
 
 
119
        ENTER1("%p, %p, %p", drv_obj, dev_name, link);
 
120
        status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0,
 
121
                                FALSE, &tmp);
 
122
 
 
123
        if (status != STATUS_SUCCESS)
 
124
                EXIT1(return NDIS_STATUS_RESOURCES);
 
125
        if (link)
 
126
                status = IoCreateSymbolicLink(link, dev_name);
 
127
        if (status != STATUS_SUCCESS) {
 
128
                IoDeleteDevice(tmp);
 
129
                EXIT1(return NDIS_STATUS_RESOURCES);
 
130
        }
 
131
 
 
132
        *dev_obj = tmp;
 
133
        *dev_obj_handle = *dev_obj;
 
134
        for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
 
135
                if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) {
 
136
                        drv_obj->major_func[i] = funcs[i];
 
137
                        TRACE1("mj_fn for 0x%x is at %p", i, funcs[i]);
 
138
                }
 
139
        EXIT1(return NDIS_STATUS_SUCCESS);
 
140
}
 
141
 
 
142
wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1)
 
143
        (struct device_object *dev_obj)
 
144
{
 
145
        ENTER2("%p", dev_obj);
 
146
        IoDeleteDevice(dev_obj);
 
147
        return NDIS_STATUS_SUCCESS;
 
148
}
 
149
 
 
150
wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3)
 
151
        (void **dest, UINT length, ULONG tag)
 
152
{
 
153
        void *addr;
 
154
 
 
155
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
156
        addr = ExAllocatePoolWithTag(NonPagedPool, length, tag);
 
157
        TRACE4("%p", addr);
 
158
        if (addr) {
 
159
                *dest = addr;
 
160
                EXIT4(return NDIS_STATUS_SUCCESS);
 
161
        } else
 
162
                EXIT4(return NDIS_STATUS_FAILURE);
 
163
}
 
164
 
 
165
wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4)
 
166
        (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address)
 
167
{
 
168
        return NdisAllocateMemoryWithTag(dest, length, 0);
 
169
}
 
170
 
 
171
/* length_tag is either length or tag, depending on if
 
172
 * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate
 
173
 * memory */
 
174
wstdcall void WIN_FUNC(NdisFreeMemory,3)
 
175
        (void *addr, UINT length_tag, UINT flags)
 
176
{
 
177
        TRACE4("%p", addr);
 
178
        ExFreePool(addr);
 
179
}
 
180
 
 
181
noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12)
 
182
        (struct driver_object *drv_obj, ULONG error, ULONG count, ...)
 
183
{
 
184
        va_list args;
 
185
        int i;
 
186
        ULONG code;
 
187
 
 
188
        va_start(args, count);
 
189
        ERROR("log: %08X, count: %d, return_address: %p",
 
190
              error, count, __builtin_return_address(0));
 
191
        for (i = 0; i < count; i++) {
 
192
                code = va_arg(args, ULONG);
 
193
                ERROR("code: 0x%x", code);
 
194
        }
 
195
        va_end(args);
 
196
        EXIT2(return);
 
197
}
 
198
 
 
199
wstdcall void WIN_FUNC(NdisOpenConfiguration,3)
 
200
        (NDIS_STATUS *status, struct ndis_mp_block **conf_handle,
 
201
         struct ndis_mp_block *handle)
 
202
{
 
203
        ENTER2("%p", conf_handle);
 
204
        *conf_handle = handle;
 
205
        *status = NDIS_STATUS_SUCCESS;
 
206
        EXIT2(return);
 
207
}
 
208
 
 
209
wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3)
 
210
        (NDIS_STATUS *status, void **confhandle,
 
211
         struct unicode_string *section)
 
212
{
 
213
        ENTER2("%p", confhandle);
 
214
        *status = NDIS_STATUS_SUCCESS;
 
215
        EXIT2(return);
 
216
}
 
217
 
 
218
wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4)
 
219
        (NDIS_STATUS *status, void *handle,
 
220
         struct unicode_string *key, void **subkeyhandle)
 
221
{
 
222
        struct ansi_string ansi;
 
223
        ENTER2("");
 
224
        if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) {
 
225
                TRACE2("%s", ansi.buf);
 
226
                RtlFreeAnsiString(&ansi);
 
227
        }
 
228
        *subkeyhandle = handle;
 
229
        *status = NDIS_STATUS_SUCCESS;
 
230
        EXIT2(return);
 
231
}
 
232
 
 
233
wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5)
 
234
        (NDIS_STATUS *status, void *handle, ULONG index,
 
235
         struct unicode_string *key, void **subkeyhandle)
 
236
{
 
237
        ENTER2("%u", index);
 
238
//      *subkeyhandle = handle;
 
239
        *status = NDIS_STATUS_FAILURE;
 
240
        EXIT2(return);
 
241
}
 
242
 
 
243
wstdcall void WIN_FUNC(NdisCloseConfiguration,1)
 
244
        (void *handle)
 
245
{
 
246
        /* instead of freeing all configuration parameters as we are
 
247
         * supposed to do here, we free them when the device is
 
248
         * removed */
 
249
        ENTER2("%p", handle);
 
250
        return;
 
251
}
 
252
 
 
253
wstdcall void WIN_FUNC(NdisOpenFile,5)
 
254
        (NDIS_STATUS *status, struct wrap_bin_file **file,
 
255
         UINT *filelength, struct unicode_string *filename,
 
256
         NDIS_PHY_ADDRESS highest_address)
 
257
{
 
258
        struct ansi_string ansi;
 
259
        struct wrap_bin_file *bin_file;
 
260
 
 
261
        ENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file);
 
262
        if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) !=
 
263
            STATUS_SUCCESS) {
 
264
                *status = NDIS_STATUS_RESOURCES;
 
265
                EXIT2(return);
 
266
        }
 
267
        TRACE2("%s", ansi.buf);
 
268
        bin_file = get_bin_file(ansi.buf);
 
269
        if (bin_file) {
 
270
                *file = bin_file;
 
271
                *filelength = bin_file->size;
 
272
                *status = NDIS_STATUS_SUCCESS;
 
273
        } else
 
274
                *status = NDIS_STATUS_FILE_NOT_FOUND;
 
275
 
 
276
        RtlFreeAnsiString(&ansi);
 
277
        EXIT2(return);
 
278
}
 
279
 
 
280
wstdcall void WIN_FUNC(NdisMapFile,3)
 
281
        (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file)
 
282
{
 
283
        ENTER2("%p", file);
 
284
 
 
285
        if (!file) {
 
286
                *status = NDIS_STATUS_ALREADY_MAPPED;
 
287
                EXIT2(return);
 
288
        }
 
289
 
 
290
        *status = NDIS_STATUS_SUCCESS;
 
291
        *mappedbuffer = file->data;
 
292
        EXIT2(return);
 
293
}
 
294
 
 
295
wstdcall void WIN_FUNC(NdisUnmapFile,1)
 
296
        (struct wrap_bin_file *file)
 
297
{
 
298
        ENTER2("%p", file);
 
299
        EXIT2(return);
 
300
}
 
301
 
 
302
wstdcall void WIN_FUNC(NdisCloseFile,1)
 
303
        (struct wrap_bin_file *file)
 
304
{
 
305
        ENTER2("%p", file);
 
306
        free_bin_file(file);
 
307
        EXIT2(return);
 
308
}
 
309
 
 
310
wstdcall void WIN_FUNC(NdisGetSystemUpTime,1)
 
311
        (ULONG *ms)
 
312
{
 
313
        *ms = 1000 * jiffies / HZ;
 
314
        EXIT5(return);
 
315
}
 
316
 
 
317
wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1)
 
318
        (ndis_buffer *buffer)
 
319
{
 
320
        ULONG n, length;
 
321
 
 
322
        if (buffer == NULL)
 
323
                EXIT2(return 0);
 
324
        if (MmGetMdlByteCount(buffer) == 0)
 
325
                EXIT2(return 1);
 
326
 
 
327
        length = MmGetMdlByteCount(buffer);
 
328
        n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length);
 
329
        TRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva,
 
330
               length, n);
 
331
        EXIT3(return n);
 
332
}
 
333
 
 
334
wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2)
 
335
        (ndis_buffer *buffer, UINT *arraysize)
 
336
{
 
337
        ENTER3("%p", buffer);
 
338
        *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer);
 
339
        EXIT3(return);
 
340
}
 
341
 
 
342
static struct ndis_configuration_parameter *
 
343
ndis_encode_setting(struct wrap_device_setting *setting,
 
344
                    enum ndis_parameter_type type)
 
345
{
 
346
        struct ansi_string ansi;
 
347
        struct ndis_configuration_parameter *param;
 
348
 
 
349
        param = setting->encoded;
 
350
        if (param) {
 
351
                if (param->type == type)
 
352
                        EXIT2(return param);
 
353
                if (param->type == NdisParameterString)
 
354
                        RtlFreeUnicodeString(&param->data.string);
 
355
                setting->encoded = NULL;
 
356
        } else
 
357
                param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0);
 
358
        if (!param) {
 
359
                ERROR("couldn't allocate memory");
 
360
                return NULL;
 
361
        }
 
362
        switch(type) {
 
363
        case NdisParameterInteger:
 
364
                param->data.integer = simple_strtol(setting->value, NULL, 0);
 
365
                TRACE2("0x%x", (ULONG)param->data.integer);
 
366
                break;
 
367
        case NdisParameterHexInteger:
 
368
                param->data.integer = simple_strtol(setting->value, NULL, 16);
 
369
                TRACE2("0x%x", (ULONG)param->data.integer);
 
370
                break;
 
371
        case NdisParameterString:
 
372
                RtlInitAnsiString(&ansi, setting->value);
 
373
                TRACE2("'%s'", ansi.buf);
 
374
                if (RtlAnsiStringToUnicodeString(&param->data.string,
 
375
                                                 &ansi, TRUE)) {
 
376
                        ExFreePool(param);
 
377
                        EXIT2(return NULL);
 
378
                }
 
379
                break;
 
380
        case NdisParameterBinary:
 
381
                param->data.integer = simple_strtol(setting->value, NULL, 2);
 
382
                TRACE2("0x%x", (ULONG)param->data.integer);
 
383
                break;
 
384
        default:
 
385
                ERROR("unknown type: %d", type);
 
386
                ExFreePool(param);
 
387
                return NULL;
 
388
        }
 
389
        param->type = type;
 
390
        setting->encoded = param;
 
391
        EXIT2(return param);
 
392
}
 
393
 
 
394
static int ndis_decode_setting(struct wrap_device_setting *setting,
 
395
                               struct ndis_configuration_parameter *param)
 
396
{
 
397
        struct ansi_string ansi;
 
398
        struct ndis_configuration_parameter *prev;
 
399
 
 
400
        ENTER2("%p, %p", setting, param);
 
401
        prev = setting->encoded;
 
402
        if (prev && prev->type == NdisParameterString) {
 
403
                RtlFreeUnicodeString(&prev->data.string);
 
404
                setting->encoded = NULL;
 
405
        }
 
406
        switch(param->type) {
 
407
        case NdisParameterInteger:
 
408
                snprintf(setting->value, sizeof(u32), "%u",
 
409
                         param->data.integer);
 
410
                setting->value[sizeof(ULONG)] = 0;
 
411
                break;
 
412
        case NdisParameterHexInteger:
 
413
                snprintf(setting->value, sizeof(u32), "%x",
 
414
                         param->data.integer);
 
415
                setting->value[sizeof(ULONG)] = 0;
 
416
                break;
 
417
        case NdisParameterString:
 
418
                ansi.buf = setting->value;
 
419
                ansi.max_length = MAX_SETTING_VALUE_LEN;
 
420
                if ((RtlUnicodeStringToAnsiString(&ansi, &param->data.string,
 
421
                                                  FALSE) != STATUS_SUCCESS)
 
422
                    || ansi.length >= MAX_SETTING_VALUE_LEN) {
 
423
                        EXIT1(return -1);
 
424
                }
 
425
                if (ansi.length == ansi.max_length)
 
426
                        ansi.length--;
 
427
                setting->value[ansi.length] = 0;
 
428
                break;
 
429
        case NdisParameterBinary:
 
430
                snprintf(setting->value, sizeof(u32), "%u",
 
431
                         param->data.integer);
 
432
                setting->value[sizeof(ULONG)] = 0;
 
433
                break;
 
434
        default:
 
435
                TRACE2("unknown setting type: %d", param->type);
 
436
                return -1;
 
437
        }
 
438
        TRACE2("setting changed %s='%s', %d", setting->name, setting->value,
 
439
               ansi.length);
 
440
        return 0;
 
441
}
 
442
 
 
443
static int read_setting(struct nt_list *setting_list, char *keyname, int length,
 
444
                        struct ndis_configuration_parameter **param,
 
445
                        enum ndis_parameter_type type)
 
446
{
 
447
        struct wrap_device_setting *setting;
 
448
        if (down_interruptible(&loader_mutex))
 
449
                WARNING("couldn't obtain loader_mutex");
 
450
        nt_list_for_each_entry(setting, setting_list, list) {
 
451
                if (strnicmp(keyname, setting->name, length) == 0) {
 
452
                        TRACE2("setting %s='%s'", keyname, setting->value);
 
453
                        up(&loader_mutex);
 
454
                        *param = ndis_encode_setting(setting, type);
 
455
                        if (*param)
 
456
                                EXIT2(return 0);
 
457
                        else
 
458
                                EXIT2(return -1);
 
459
                }
 
460
        }
 
461
        up(&loader_mutex);
 
462
        EXIT2(return -1);
 
463
}
 
464
 
 
465
wstdcall void WIN_FUNC(NdisReadConfiguration,5)
 
466
        (NDIS_STATUS *status, struct ndis_configuration_parameter **param,
 
467
         struct ndis_mp_block *nmb, struct unicode_string *key,
 
468
         enum ndis_parameter_type type)
 
469
{
 
470
        struct ansi_string ansi;
 
471
        int ret;
 
472
 
 
473
        ENTER2("nmb: %p", nmb);
 
474
        ret = RtlUnicodeStringToAnsiString(&ansi, key, TRUE);
 
475
        if (ret != STATUS_SUCCESS || ansi.buf == NULL) {
 
476
                *param = NULL;
 
477
                *status = NDIS_STATUS_FAILURE;
 
478
                RtlFreeAnsiString(&ansi);
 
479
                EXIT2(return);
 
480
        }
 
481
        TRACE2("%d, %s", type, ansi.buf);
 
482
 
 
483
        if (read_setting(&nmb->wnd->wd->settings, ansi.buf,
 
484
                         ansi.length, param, type) == 0 ||
 
485
            read_setting(&nmb->wnd->wd->driver->settings, ansi.buf,
 
486
                         ansi.length, param, type) == 0)
 
487
                *status = NDIS_STATUS_SUCCESS;
 
488
        else {
 
489
                TRACE2("setting %s not found (type:%d)", ansi.buf, type);
 
490
                *status = NDIS_STATUS_FAILURE;
 
491
        }
 
492
        RtlFreeAnsiString(&ansi);
 
493
        EXIT2(return);
 
494
 
 
495
}
 
496
 
 
497
wstdcall void WIN_FUNC(NdisWriteConfiguration,4)
 
498
        (NDIS_STATUS *status, struct ndis_mp_block *nmb,
 
499
         struct unicode_string *key, struct ndis_configuration_parameter *param)
 
500
{
 
501
        struct ansi_string ansi;
 
502
        char *keyname;
 
503
        struct wrap_device_setting *setting;
 
504
 
 
505
        ENTER2("nmb: %p", nmb);
 
506
        if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE)) {
 
507
                *status = NDIS_STATUS_FAILURE;
 
508
                EXIT2(return);
 
509
        }
 
510
        keyname = ansi.buf;
 
511
        TRACE2("%s", keyname);
 
512
 
 
513
        if (down_interruptible(&loader_mutex))
 
514
                WARNING("couldn't obtain loader_mutex");
 
515
        nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) {
 
516
                if (strnicmp(keyname, setting->name, ansi.length) == 0) {
 
517
                        up(&loader_mutex);
 
518
                        if (ndis_decode_setting(setting, param))
 
519
                                *status = NDIS_STATUS_FAILURE;
 
520
                        else
 
521
                                *status = NDIS_STATUS_SUCCESS;
 
522
                        RtlFreeAnsiString(&ansi);
 
523
                        EXIT2(return);
 
524
                }
 
525
        }
 
526
        up(&loader_mutex);
 
527
        setting = kzalloc(sizeof(*setting), GFP_KERNEL);
 
528
        if (setting) {
 
529
                if (ansi.length == ansi.max_length)
 
530
                        ansi.length--;
 
531
                memcpy(setting->name, keyname, ansi.length);
 
532
                setting->name[ansi.length] = 0;
 
533
                if (ndis_decode_setting(setting, param))
 
534
                        *status = NDIS_STATUS_FAILURE;
 
535
                else {
 
536
                        *status = NDIS_STATUS_SUCCESS;
 
537
                        if (down_interruptible(&loader_mutex))
 
538
                                WARNING("couldn't obtain loader_mutex");
 
539
                        InsertTailList(&nmb->wnd->wd->settings, &setting->list);
 
540
                        up(&loader_mutex);
 
541
                }
 
542
        } else
 
543
                *status = NDIS_STATUS_RESOURCES;
 
544
 
 
545
        RtlFreeAnsiString(&ansi);
 
546
        EXIT2(return);
 
547
}
 
548
 
 
549
wstdcall void WIN_FUNC(NdisReadNetworkAddress,4)
 
550
        (NDIS_STATUS *status, void **addr, UINT *len,
 
551
         struct ndis_mp_block *nmb)
 
552
{
 
553
        struct ndis_device *wnd = nmb->wnd;
 
554
        struct ndis_configuration_parameter *param;
 
555
        struct unicode_string key;
 
556
        struct ansi_string ansi;
 
557
        typeof(wnd->mac) mac;
 
558
        int i, ret;
 
559
 
 
560
        ENTER2("%p", nmb);
 
561
        RtlInitAnsiString(&ansi, "NetworkAddress");
 
562
        *status = NDIS_STATUS_FAILURE;
 
563
        if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS)
 
564
                EXIT1(return);
 
565
 
 
566
        NdisReadConfiguration(&ret, &param, nmb, &key, NdisParameterString);
 
567
        RtlFreeUnicodeString(&key);
 
568
        if (ret != NDIS_STATUS_SUCCESS)
 
569
                EXIT1(return);
 
570
        ret = RtlUnicodeStringToAnsiString(&ansi, &param->data.string, TRUE);
 
571
        if (ret != STATUS_SUCCESS)
 
572
                EXIT1(return);
 
573
 
 
574
        i = 0;
 
575
        if (ansi.length >= 2 * sizeof(mac)) {
 
576
                for (i = 0; i < sizeof(mac); i++) {
 
577
                        char c[3];
 
578
                        int x;
 
579
                        c[0] = ansi.buf[i*2];
 
580
                        c[1] = ansi.buf[i*2+1];
 
581
                        c[2] = 0;
 
582
                        ret = sscanf(c, "%x", &x);
 
583
                        if (ret != 1)
 
584
                                break;
 
585
                        mac[i] = x;
 
586
                }
 
587
        }
 
588
        TRACE2("%s, %d, " MACSTR, ansi.buf, i, MAC2STR(mac));
 
589
        RtlFreeAnsiString(&ansi);
 
590
        if (i == sizeof(mac)) {
 
591
                memcpy(wnd->mac, mac, sizeof(wnd->mac));
 
592
                *len = sizeof(mac);
 
593
                *addr = wnd->mac;
 
594
                *status = NDIS_STATUS_SUCCESS;
 
595
        }
 
596
        EXIT1(return);
 
597
}
 
598
 
 
599
wstdcall void WIN_FUNC(NdisInitializeString,2)
 
600
        (struct unicode_string *dest, UCHAR *src)
 
601
{
 
602
        struct ansi_string ansi;
 
603
 
 
604
        ENTER2("");
 
605
        if (src == NULL) {
 
606
                dest->length = dest->max_length = 0;
 
607
                dest->buf = NULL;
 
608
        } else {
 
609
                RtlInitAnsiString(&ansi, src);
 
610
                /* the string is freed with NdisFreeMemory */
 
611
                RtlAnsiStringToUnicodeString(dest, &ansi, TRUE);
 
612
        }
 
613
        EXIT2(return);
 
614
}
 
615
 
 
616
wstdcall void WIN_FUNC(NdisInitAnsiString,2)
 
617
        (struct ansi_string *dst, CHAR *src)
 
618
{
 
619
        RtlInitAnsiString(dst, src);
 
620
        EXIT2(return);
 
621
}
 
622
 
 
623
wstdcall void WIN_FUNC(NdisInitUnicodeString,2)
 
624
        (struct unicode_string *dest, const wchar_t *src)
 
625
{
 
626
        RtlInitUnicodeString(dest, src);
 
627
        return;
 
628
}
 
629
 
 
630
wstdcall NDIS_STATUS WIN_FUNC(NdisAnsiStringToUnicodeString,2)
 
631
        (struct unicode_string *dst, struct ansi_string *src)
 
632
{
 
633
        ENTER2("");
 
634
        if (dst == NULL || src == NULL)
 
635
                EXIT2(return NDIS_STATUS_FAILURE);
 
636
        if (RtlAnsiStringToUnicodeString(dst, src, FALSE) == STATUS_SUCCESS)
 
637
                return NDIS_STATUS_SUCCESS;
 
638
        else
 
639
                return NDIS_STATUS_FAILURE;
 
640
}
 
641
 
 
642
wstdcall NDIS_STATUS WIN_FUNC(NdisUnicodeStringToAnsiString,2)
 
643
        (struct ansi_string *dst, struct unicode_string *src)
 
644
{
 
645
        ENTER2("");
 
646
        if (dst == NULL || src == NULL)
 
647
                EXIT2(return NDIS_STATUS_FAILURE);
 
648
        if (RtlUnicodeStringToAnsiString(dst, src, FALSE) == STATUS_SUCCESS)
 
649
                return NDIS_STATUS_SUCCESS;
 
650
        else
 
651
                return NDIS_STATUS_FAILURE;
 
652
}
 
653
 
 
654
wstdcall NTSTATUS WIN_FUNC(NdisUpcaseUnicodeString,2)
 
655
        (struct unicode_string *dst, struct unicode_string *src)
 
656
{
 
657
        EXIT2(return RtlUpcaseUnicodeString(dst, src, FALSE));
 
658
}
 
659
 
 
660
wstdcall void WIN_FUNC(NdisMSetAttributesEx,5)
 
661
        (struct ndis_mp_block *nmb, void *mp_ctx,
 
662
         UINT hangcheck_interval, UINT attributes, ULONG adaptertype)
 
663
{
 
664
        struct ndis_device *wnd;
 
665
 
 
666
        ENTER1("%p, %p, %d, %08x, %d", nmb, mp_ctx, hangcheck_interval,
 
667
               attributes, adaptertype);
 
668
        wnd = nmb->wnd;
 
669
        nmb->mp_ctx = mp_ctx;
 
670
        wnd->attributes = attributes;
 
671
 
 
672
        if ((attributes & NDIS_ATTRIBUTE_BUS_MASTER) &&
 
673
            wrap_is_pci_bus(wnd->wd->dev_bus))
 
674
                pci_set_master(wnd->wd->pci.pdev);
 
675
 
 
676
        if (hangcheck_interval > 0)
 
677
                wnd->hangcheck_interval = 2 * hangcheck_interval * HZ;
 
678
        else
 
679
                wnd->hangcheck_interval = 2 * HZ;
 
680
 
 
681
        EXIT1(return);
 
682
}
 
683
 
 
684
wstdcall ULONG WIN_FUNC(NdisReadPciSlotInformation,5)
 
685
        (struct ndis_mp_block *nmb, ULONG slot,
 
686
         ULONG offset, char *buf, ULONG len)
 
687
{
 
688
        struct wrap_device *wd = nmb->wnd->wd;
 
689
        ULONG i;
 
690
        for (i = 0; i < len; i++)
 
691
                if (pci_read_config_byte(wd->pci.pdev, offset + i, &buf[i]) !=
 
692
                    PCIBIOS_SUCCESSFUL)
 
693
                        break;
 
694
        DBG_BLOCK(2) {
 
695
                if (i != len)
 
696
                        WARNING("%u, %u", i, len);
 
697
        }
 
698
        return i;
 
699
}
 
700
 
 
701
wstdcall ULONG WIN_FUNC(NdisImmediateReadPciSlotInformation,5)
 
702
        (struct ndis_mp_block *nmb, ULONG slot,
 
703
         ULONG offset, char *buf, ULONG len)
 
704
{
 
705
        return NdisReadPciSlotInformation(nmb, slot, offset, buf, len);
 
706
}
 
707
 
 
708
wstdcall ULONG WIN_FUNC(NdisWritePciSlotInformation,5)
 
709
        (struct ndis_mp_block *nmb, ULONG slot,
 
710
         ULONG offset, char *buf, ULONG len)
 
711
{
 
712
        struct wrap_device *wd = nmb->wnd->wd;
 
713
        ULONG i;
 
714
        for (i = 0; i < len; i++)
 
715
                if (pci_write_config_byte(wd->pci.pdev, offset + i, buf[i]) !=
 
716
                    PCIBIOS_SUCCESSFUL)
 
717
                        break;
 
718
        DBG_BLOCK(2) {
 
719
                if (i != len)
 
720
                        WARNING("%u, %u", i, len);
 
721
        }
 
722
        return i;
 
723
}
 
724
 
 
725
wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterIoPortRange,4)
 
726
        (void **virt, struct ndis_mp_block *nmb, UINT start, UINT len)
 
727
{
 
728
        ENTER3("%08x %08x", start, len);
 
729
        *virt = (void *)(ULONG_PTR)start;
 
730
        return NDIS_STATUS_SUCCESS;
 
731
}
 
732
 
 
733
wstdcall void WIN_FUNC(NdisMDeregisterIoPortRange,4)
 
734
        (struct ndis_mp_block *nmb, UINT start, UINT len, void* virt)
 
735
{
 
736
        ENTER1("%08x %08x", start, len);
 
737
}
 
738
 
 
739
wstdcall void WIN_FUNC(NdisReadPortUchar,3)
 
740
        (struct ndis_mp_block *nmb, ULONG port, char *data)
 
741
{
 
742
        *data = inb(port);
 
743
}
 
744
 
 
745
wstdcall void WIN_FUNC(NdisImmediateReadPortUchar,3)
 
746
        (struct ndis_mp_block *nmb, ULONG port, char *data)
 
747
{
 
748
        *data = inb(port);
 
749
}
 
750
 
 
751
wstdcall void WIN_FUNC(NdisWritePortUchar,3)
 
752
        (struct ndis_mp_block *nmb, ULONG port, char data)
 
753
{
 
754
        outb(data, port);
 
755
}
 
756
 
 
757
wstdcall void WIN_FUNC(NdisImmediateWritePortUchar,3)
 
758
        (struct ndis_mp_block *nmb, ULONG port, char data)
 
759
{
 
760
        outb(data, port);
 
761
}
 
762
 
 
763
wstdcall void WIN_FUNC(NdisMQueryAdapterResources,4)
 
764
        (NDIS_STATUS *status, struct ndis_mp_block *nmb,
 
765
         NDIS_RESOURCE_LIST *resource_list, UINT *size)
 
766
{
 
767
        struct ndis_device *wnd = nmb->wnd;
 
768
        NDIS_RESOURCE_LIST *list;
 
769
        UINT resource_length;
 
770
 
 
771
        list = &wnd->wd->resource_list->list->partial_resource_list;
 
772
        resource_length = sizeof(struct cm_partial_resource_list) +
 
773
                sizeof(struct cm_partial_resource_descriptor) *
 
774
                (list->count - 1);
 
775
        TRACE2("%p, %p,%d (%d), %p %d %d", wnd, resource_list, *size,
 
776
               resource_length, &list->partial_descriptors[list->count-1],
 
777
               list->partial_descriptors[list->count-1].u.interrupt.level,
 
778
               list->partial_descriptors[list->count-1].u.interrupt.vector);
 
779
        if (*size < sizeof(*list)) {
 
780
                *size = resource_length;
 
781
                *status = NDIS_STATUS_BUFFER_TOO_SHORT;
 
782
        } else {
 
783
                ULONG count;
 
784
                if (*size >= resource_length) {
 
785
                        *size = resource_length;
 
786
                        count = list->count;
 
787
                } else {
 
788
                        UINT n = sizeof(*list);
 
789
                        count = 1;
 
790
                        while (count++ < list->count && n < *size)
 
791
                                n += sizeof(list->partial_descriptors);
 
792
                        *size = n;
 
793
                }
 
794
                memcpy(resource_list, list, *size);
 
795
                resource_list->count = count;
 
796
                *status = NDIS_STATUS_SUCCESS;
 
797
        }
 
798
        EXIT2(return);
 
799
}
 
800
 
 
801
wstdcall NDIS_STATUS WIN_FUNC(NdisMPciAssignResources,3)
 
802
        (struct ndis_mp_block *nmb, ULONG slot_number,
 
803
         NDIS_RESOURCE_LIST **resources)
 
804
{
 
805
        struct ndis_device *wnd = nmb->wnd;
 
806
 
 
807
        ENTER2("%p, %p", wnd, wnd->wd->resource_list);
 
808
        *resources = &wnd->wd->resource_list->list->partial_resource_list;
 
809
        EXIT2(return NDIS_STATUS_SUCCESS);
 
810
}
 
811
 
 
812
wstdcall NDIS_STATUS WIN_FUNC(NdisMMapIoSpace,4)
 
813
        (void __iomem **virt, struct ndis_mp_block *nmb,
 
814
         NDIS_PHY_ADDRESS phy_addr, UINT len)
 
815
{
 
816
        struct ndis_device *wnd = nmb->wnd;
 
817
 
 
818
        ENTER2("%Lx, %d", phy_addr, len);
 
819
        *virt = MmMapIoSpace(phy_addr, len, MmCached);
 
820
        if (*virt == NULL) {
 
821
                ERROR("ioremap failed");
 
822
                EXIT2(return NDIS_STATUS_FAILURE);
 
823
        }
 
824
        wnd->mem_start = phy_addr;
 
825
        wnd->mem_end = phy_addr + len;
 
826
        TRACE2("%p", *virt);
 
827
        EXIT2(return NDIS_STATUS_SUCCESS);
 
828
}
 
829
 
 
830
wstdcall void WIN_FUNC(NdisMUnmapIoSpace,3)
 
831
        (struct ndis_mp_block *nmb, void __iomem *virt, UINT len)
 
832
{
 
833
        ENTER2("%p, %d", virt, len);
 
834
        MmUnmapIoSpace(virt, len);
 
835
        EXIT2(return);
 
836
}
 
837
 
 
838
wstdcall void WIN_FUNC(NdisAllocateSpinLock,1)
 
839
        (struct ndis_spinlock *lock)
 
840
{
 
841
        TRACE4("lock %p, %p", lock, &lock->klock);
 
842
        KeInitializeSpinLock(&lock->klock);
 
843
        lock->irql = PASSIVE_LEVEL;
 
844
        return;
 
845
}
 
846
 
 
847
wstdcall void WIN_FUNC(NdisFreeSpinLock,1)
 
848
        (struct ndis_spinlock *lock)
 
849
{
 
850
        TRACE4("lock %p, %p", lock, &lock->klock);
 
851
        return;
 
852
}
 
853
 
 
854
wstdcall void WIN_FUNC(NdisAcquireSpinLock,1)
 
855
        (struct ndis_spinlock *lock)
 
856
{
 
857
        ENTER6("lock %p, %p", lock, &lock->klock);
 
858
//      assert_irql(_irql_ <= DISPATCH_LEVEL);
 
859
        lock->irql = nt_spin_lock_irql(&lock->klock, DISPATCH_LEVEL);
 
860
        return;
 
861
}
 
862
 
 
863
wstdcall void WIN_FUNC(NdisReleaseSpinLock,1)
 
864
        (struct ndis_spinlock *lock)
 
865
{
 
866
        ENTER6("lock %p, %p", lock, &lock->klock);
 
867
//      assert_irql(_irql_ == DISPATCH_LEVEL);
 
868
        nt_spin_unlock_irql(&lock->klock, lock->irql);
 
869
        return;
 
870
}
 
871
 
 
872
wstdcall void WIN_FUNC(NdisDprAcquireSpinLock,1)
 
873
        (struct ndis_spinlock *lock)
 
874
{
 
875
        ENTER6("lock %p", &lock->klock);
 
876
//      assert_irql(_irql_ == DISPATCH_LEVEL);
 
877
        nt_spin_lock(&lock->klock);
 
878
        return;
 
879
}
 
880
 
 
881
wstdcall void WIN_FUNC(NdisDprReleaseSpinLock,1)
 
882
        (struct ndis_spinlock *lock)
 
883
{
 
884
        ENTER6("lock %p", &lock->klock);
 
885
//      assert_irql(_irql_ == DISPATCH_LEVEL);
 
886
        nt_spin_unlock(&lock->klock);
 
887
        return;
 
888
}
 
889
 
 
890
wstdcall void WIN_FUNC(NdisInitializeReadWriteLock,1)
 
891
        (struct ndis_rw_lock *rw_lock)
 
892
{
 
893
        ENTER3("%p", rw_lock);
 
894
        memset(rw_lock, 0, sizeof(*rw_lock));
 
895
        KeInitializeSpinLock(&rw_lock->klock);
 
896
        return;
 
897
}
 
898
 
 
899
/* read/write locks are implemented in a rather simplisitic way - we
 
900
 * should probably use Linux's rw_lock implementation */
 
901
 
 
902
wstdcall void WIN_FUNC(NdisAcquireReadWriteLock,3)
 
903
        (struct ndis_rw_lock *rw_lock, BOOLEAN write,
 
904
         struct lock_state *lock_state)
 
905
{
 
906
        if (write) {
 
907
                while (1) {
 
908
                        if (cmpxchg(&rw_lock->count, 0, -1) == 0)
 
909
                                return;
 
910
                        while (rw_lock->count)
 
911
                                cpu_relax();
 
912
                }
 
913
                return;
 
914
        }
 
915
        while (1) {
 
916
                typeof(rw_lock->count) count;
 
917
                while ((count = rw_lock->count) < 0)
 
918
                        cpu_relax();
 
919
                if (cmpxchg(&rw_lock->count, count, count + 1) == count)
 
920
                        return;
 
921
        }
 
922
}
 
923
 
 
924
wstdcall void WIN_FUNC(NdisReleaseReadWriteLock,2)
 
925
        (struct ndis_rw_lock *rw_lock, struct lock_state *lock_state)
 
926
{
 
927
        if (rw_lock->count > 0)
 
928
                pre_atomic_add(rw_lock->count, -1);
 
929
        else if (rw_lock->count == -1)
 
930
                rw_lock->count = 0;
 
931
        else
 
932
                WARNING("invalid state: %d", rw_lock->count);
 
933
}
 
934
 
 
935
wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateMapRegisters,5)
 
936
        (struct ndis_mp_block *nmb, UINT dmachan,
 
937
         NDIS_DMA_SIZE dmasize, ULONG basemap, ULONG max_buf_size)
 
938
{
 
939
        struct ndis_device *wnd = nmb->wnd;
 
940
 
 
941
        ENTER2("%p, %d %d %d %d", wnd, dmachan, dmasize, basemap, max_buf_size);
 
942
        if (wnd->dma_map_count > 0) {
 
943
                WARNING("%s: map registers already allocated: %u",
 
944
                        wnd->net_dev->name, wnd->dma_map_count);
 
945
                EXIT2(return NDIS_STATUS_RESOURCES);
 
946
        }
 
947
        if (dmasize == NDIS_DMA_24BITS) {
 
948
                if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(24)) ||
 
949
                    pci_set_consistent_dma_mask(wnd->wd->pci.pdev,
 
950
                                                DMA_BIT_MASK(24)))
 
951
                        WARNING("setting dma mask failed");
 
952
        } else if (dmasize == NDIS_DMA_32BITS) {
 
953
                /* consistent dma is in low 32-bits by default */
 
954
                if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)))
 
955
                        WARNING("setting dma mask failed");
 
956
#ifdef CONFIG_X86_64
 
957
        } else if (dmasize == NDIS_DMA_64BITS) {
 
958
                if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(64)) ||
 
959
                    pci_set_consistent_dma_mask(wnd->wd->pci.pdev,
 
960
                                                DMA_BIT_MASK(64)))
 
961
                        WARNING("setting dma mask failed");
 
962
                else
 
963
                        wnd->net_dev->features |= NETIF_F_HIGHDMA;
 
964
#endif
 
965
        }
 
966
        /* since memory for buffer is allocated with kmalloc, buffer
 
967
         * is physically contiguous, so entire map will fit in one
 
968
         * register */
 
969
        if (basemap > 64) {
 
970
                WARNING("Windows driver %s requesting too many (%u) "
 
971
                        "map registers", wnd->wd->driver->name, basemap);
 
972
                /* As per NDIS, NDIS_STATUS_RESOURCES should be
 
973
                 * returned, but with that Atheros PCI driver fails -
 
974
                 * for now tolerate it */
 
975
//              EXIT2(return NDIS_STATUS_RESOURCES);
 
976
        }
 
977
 
 
978
        wnd->dma_map_addr = kmalloc(basemap * sizeof(*(wnd->dma_map_addr)),
 
979
                                    GFP_KERNEL);
 
980
        if (!wnd->dma_map_addr)
 
981
                EXIT2(return NDIS_STATUS_RESOURCES);
 
982
        memset(wnd->dma_map_addr, 0, basemap * sizeof(*(wnd->dma_map_addr)));
 
983
        wnd->dma_map_count = basemap;
 
984
        TRACE2("%u", wnd->dma_map_count);
 
985
        EXIT2(return NDIS_STATUS_SUCCESS);
 
986
}
 
987
 
 
988
wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1)
 
989
        (struct ndis_mp_block *nmb)
 
990
{
 
991
        struct ndis_device *wnd = nmb->wnd;
 
992
        int i;
 
993
 
 
994
        ENTER2("wnd: %p", wnd);
 
995
        if (wnd->dma_map_addr) {
 
996
                for (i = 0; i < wnd->dma_map_count; i++) {
 
997
                        if (wnd->dma_map_addr[i])
 
998
                                WARNING("%s: dma addr %p not freed by "
 
999
                                        "Windows driver", wnd->net_dev->name,
 
1000
                                        (void *)wnd->dma_map_addr[i]);
 
1001
                }
 
1002
                kfree(wnd->dma_map_addr);
 
1003
                wnd->dma_map_addr = NULL;
 
1004
        } else
 
1005
                WARNING("map registers already freed?");
 
1006
        wnd->dma_map_count = 0;
 
1007
        EXIT2(return);
 
1008
}
 
1009
 
 
1010
wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6)
 
1011
        (struct ndis_mp_block *nmb, ndis_buffer *buf,
 
1012
         ULONG index, BOOLEAN write_to_dev,
 
1013
         struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size)
 
1014
{
 
1015
        struct ndis_device *wnd = nmb->wnd;
 
1016
 
 
1017
        ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count);
 
1018
        if (unlikely(wnd->sg_dma_size || !write_to_dev ||
 
1019
                     index >= wnd->dma_map_count)) {
 
1020
                WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size,
 
1021
                        write_to_dev, index, wnd->dma_map_count);
 
1022
                phy_addr_array[0].phy_addr = 0;
 
1023
                phy_addr_array[0].length = 0;
 
1024
                *array_size = 0;
 
1025
                return;
 
1026
        }
 
1027
        if (wnd->dma_map_addr[index]) {
 
1028
                TRACE2("buffer %p at %d is already mapped: %lx", buf, index,
 
1029
                       (unsigned long)wnd->dma_map_addr[index]);
 
1030
//              *array_size = 1;
 
1031
                return;
 
1032
        }
 
1033
        TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf),
 
1034
               MmGetMdlByteCount(buf));
 
1035
        DBG_BLOCK(4) {
 
1036
                dump_bytes(__func__, MmGetSystemAddressForMdl(buf),
 
1037
                           MmGetMdlByteCount(buf));
 
1038
        }
 
1039
        wnd->dma_map_addr[index] =
 
1040
                PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev,
 
1041
                                   MmGetSystemAddressForMdl(buf),
 
1042
                                   MmGetMdlByteCount(buf), PCI_DMA_TODEVICE);
 
1043
        phy_addr_array[0].phy_addr = wnd->dma_map_addr[index];
 
1044
        phy_addr_array[0].length = MmGetMdlByteCount(buf);
 
1045
        TRACE4("%Lx, %d, %d", phy_addr_array[0].phy_addr,
 
1046
               phy_addr_array[0].length, index);
 
1047
        *array_size = 1;
 
1048
}
 
1049
 
 
1050
wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3)
 
1051
        (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index)
 
1052
{
 
1053
        struct ndis_device *wnd = nmb->wnd;
 
1054
 
 
1055
        ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count);
 
1056
 
 
1057
        if (unlikely(wnd->sg_dma_size))
 
1058
                WARNING("buffer %p may have been unmapped already", buf);
 
1059
        if (index >= wnd->dma_map_count) {
 
1060
                ERROR("invalid map register (%u >= %u)",
 
1061
                      index, wnd->dma_map_count);
 
1062
                return;
 
1063
        }
 
1064
        TRACE4("%lx", (unsigned long)wnd->dma_map_addr[index]);
 
1065
        if (wnd->dma_map_addr[index]) {
 
1066
                PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index],
 
1067
                                     MmGetMdlByteCount(buf), PCI_DMA_TODEVICE);
 
1068
                wnd->dma_map_addr[index] = 0;
 
1069
        } else
 
1070
                WARNING("map registers at %u not used", index);
 
1071
}
 
1072
 
 
1073
wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5)
 
1074
        (struct ndis_mp_block *nmb, ULONG size,
 
1075
         BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys)
 
1076
{
 
1077
        dma_addr_t dma_addr;
 
1078
        struct wrap_device *wd = nmb->wnd->wd;
 
1079
 
 
1080
        ENTER3("size: %u, cached: %d", size, cached);
 
1081
        *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr);
 
1082
        if (*virt)
 
1083
                *phys = dma_addr;
 
1084
        else
 
1085
                WARNING("couldn't allocate %d bytes of %scached DMA memory",
 
1086
                        size, cached ? "" : "un-");
 
1087
        EXIT3(return);
 
1088
}
 
1089
 
 
1090
wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5)
 
1091
        (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached,
 
1092
         void *virt, NDIS_PHY_ADDRESS addr)
 
1093
{
 
1094
        struct wrap_device *wd = nmb->wnd->wd;
 
1095
        ENTER3("%p, %Lx, %u", virt, addr, size);
 
1096
        PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr);
 
1097
        EXIT3(return);
 
1098
}
 
1099
 
 
1100
wstdcall void alloc_shared_memory_async(void *arg1, void *arg2)
 
1101
{
 
1102
        struct ndis_device *wnd;
 
1103
        struct alloc_shared_mem *alloc_shared_mem;
 
1104
        struct miniport *mp;
 
1105
        void *virt;
 
1106
        NDIS_PHY_ADDRESS phys;
 
1107
        KIRQL irql;
 
1108
 
 
1109
        wnd = arg1;
 
1110
        alloc_shared_mem = arg2;
 
1111
        mp = &wnd->wd->driver->ndis_driver->mp;
 
1112
        NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size,
 
1113
                                  alloc_shared_mem->cached, &virt, &phys);
 
1114
        irql = serialize_lock_irql(wnd);
 
1115
        assert_irql(_irql_ == DISPATCH_LEVEL);
 
1116
        LIN2WIN5(mp->alloc_complete, wnd->nmb, virt,
 
1117
                 &phys, alloc_shared_mem->size, alloc_shared_mem->ctx);
 
1118
        serialize_unlock_irql(wnd, irql);
 
1119
        kfree(alloc_shared_mem);
 
1120
}
 
1121
WIN_FUNC_DECL(alloc_shared_memory_async,2)
 
1122
 
 
1123
wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4)
 
1124
        (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx)
 
1125
{
 
1126
        struct ndis_device *wnd = nmb->wnd;
 
1127
        struct alloc_shared_mem *alloc_shared_mem;
 
1128
 
 
1129
        ENTER3("wnd: %p", wnd);
 
1130
        alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp());
 
1131
        if (!alloc_shared_mem) {
 
1132
                WARNING("couldn't allocate memory");
 
1133
                return NDIS_STATUS_FAILURE;
 
1134
        }
 
1135
 
 
1136
        alloc_shared_mem->size = size;
 
1137
        alloc_shared_mem->cached = cached;
 
1138
        alloc_shared_mem->ctx = ctx;
 
1139
        if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2),
 
1140
                                    wnd, alloc_shared_mem))
 
1141
                EXIT3(return NDIS_STATUS_FAILURE);
 
1142
        EXIT3(return NDIS_STATUS_PENDING);
 
1143
}
 
1144
 
 
1145
/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of
 
1146
 * allocating and freeing with kernel functions, we chain them into
 
1147
 * ndis_buffer_pool. When an MDL is freed, it is added to the list of
 
1148
 * free MDLs. When allocated, we first check if there is one in free
 
1149
 * list and if so just return it; otherwise, we allocate a new one and
 
1150
 * return that. This reduces memory fragmentation. Windows DDK says
 
1151
 * that the driver itself shouldn't check what is returned in
 
1152
 * pool_handle, presumably because buffer pools are not used in
 
1153
 * XP. However, as long as driver follows rest of the semantics - that
 
1154
 * it should indicate maximum number of MDLs used with num_descr and
 
1155
 * pass the same pool_handle in other buffer functions, this should
 
1156
 * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle,
 
1157
 * so we use 'process' field of MDL to store pool_handle. */
 
1158
 
 
1159
wstdcall void WIN_FUNC(NdisAllocateBufferPool,3)
 
1160
        (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle,
 
1161
         UINT num_descr)
 
1162
{
 
1163
        struct ndis_buffer_pool *pool;
 
1164
 
 
1165
        ENTER1("buffers: %d", num_descr);
 
1166
        pool = kmalloc(sizeof(*pool), irql_gfp());
 
1167
        if (!pool) {
 
1168
                *status = NDIS_STATUS_RESOURCES;
 
1169
                EXIT3(return);
 
1170
        }
 
1171
        spin_lock_init(&pool->lock);
 
1172
        pool->max_descr = num_descr;
 
1173
        pool->num_allocated_descr = 0;
 
1174
        pool->free_descr = NULL;
 
1175
        *pool_handle = pool;
 
1176
        *status = NDIS_STATUS_SUCCESS;
 
1177
        TRACE1("pool: %p, num_descr: %d", pool, num_descr);
 
1178
        EXIT1(return);
 
1179
}
 
1180
 
 
1181
wstdcall void WIN_FUNC(NdisAllocateBuffer,5)
 
1182
        (NDIS_STATUS *status, ndis_buffer **buffer,
 
1183
         struct ndis_buffer_pool *pool, void *virt, UINT length)
 
1184
{
 
1185
        ndis_buffer *descr;
 
1186
 
 
1187
        ENTER4("pool: %p (%d)", pool, pool->num_allocated_descr);
 
1188
        /* NDIS drivers should call this at DISPATCH_LEVEL, but
 
1189
         * alloc_tx_packet calls at SOFT_IRQL */
 
1190
        assert_irql(_irql_ <= SOFT_LEVEL);
 
1191
        if (!pool) {
 
1192
                *status = NDIS_STATUS_FAILURE;
 
1193
                *buffer = NULL;
 
1194
                EXIT4(return);
 
1195
        }
 
1196
        spin_lock_bh(&pool->lock);
 
1197
        if ((descr = pool->free_descr))
 
1198
                pool->free_descr = descr->next;
 
1199
        spin_unlock_bh(&pool->lock);
 
1200
        if (descr) {
 
1201
                typeof(descr->flags) flags;
 
1202
                flags = descr->flags;
 
1203
                memset(descr, 0, sizeof(*descr));
 
1204
                MmInitializeMdl(descr, virt, length);
 
1205
                if (flags & MDL_CACHE_ALLOCATED)
 
1206
                        descr->flags |= MDL_CACHE_ALLOCATED;
 
1207
        } else {
 
1208
                if (pool->num_allocated_descr > pool->max_descr) {
 
1209
                        TRACE2("pool %p is full: %d(%d)", pool,
 
1210
                               pool->num_allocated_descr, pool->max_descr);
 
1211
#ifndef ALLOW_POOL_OVERFLOW
 
1212
                        *status = NDIS_STATUS_FAILURE;
 
1213
                        *buffer = NULL;
 
1214
                        return;
 
1215
#endif
 
1216
                }
 
1217
                descr = allocate_init_mdl(virt, length);
 
1218
                if (!descr) {
 
1219
                        WARNING("couldn't allocate buffer");
 
1220
                        *status = NDIS_STATUS_FAILURE;
 
1221
                        *buffer = NULL;
 
1222
                        EXIT4(return);
 
1223
                }
 
1224
                TRACE4("buffer %p for %p, %d", descr, virt, length);
 
1225
                atomic_inc_var(pool->num_allocated_descr);
 
1226
        }
 
1227
        /* TODO: make sure this mdl can map given buffer */
 
1228
        MmBuildMdlForNonPagedPool(descr);
 
1229
//      descr->flags |= MDL_ALLOCATED_FIXED_SIZE |
 
1230
//              MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED;
 
1231
        descr->pool = pool;
 
1232
        *buffer = descr;
 
1233
        *status = NDIS_STATUS_SUCCESS;
 
1234
        TRACE4("buffer: %p", descr);
 
1235
        EXIT4(return);
 
1236
}
 
1237
 
 
1238
wstdcall void WIN_FUNC(NdisFreeBuffer,1)
 
1239
        (ndis_buffer *buffer)
 
1240
{
 
1241
        struct ndis_buffer_pool *pool;
 
1242
 
 
1243
        ENTER4("%p", buffer);
 
1244
        if (!buffer || !buffer->pool) {
 
1245
                ERROR("invalid buffer");
 
1246
                EXIT4(return);
 
1247
        }
 
1248
        pool = buffer->pool;
 
1249
        if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) {
 
1250
                /* NB NB NB: set mdl's 'pool' field to NULL before
 
1251
                 * calling free_mdl; otherwise free_mdl calls
 
1252
                 * NdisFreeBuffer back */
 
1253
                atomic_dec_var(pool->num_allocated_descr);
 
1254
                buffer->pool = NULL;
 
1255
                free_mdl(buffer);
 
1256
        } else {
 
1257
                spin_lock_bh(&pool->lock);
 
1258
                buffer->next = pool->free_descr;
 
1259
                pool->free_descr = buffer;
 
1260
                spin_unlock_bh(&pool->lock);
 
1261
        }
 
1262
        EXIT4(return);
 
1263
}
 
1264
 
 
1265
wstdcall void WIN_FUNC(NdisFreeBufferPool,1)
 
1266
        (struct ndis_buffer_pool *pool)
 
1267
{
 
1268
        ndis_buffer *cur, *next;
 
1269
 
 
1270
        TRACE3("pool: %p", pool);
 
1271
        if (!pool) {
 
1272
                WARNING("invalid pool");
 
1273
                EXIT3(return);
 
1274
        }
 
1275
        spin_lock_bh(&pool->lock);
 
1276
        cur = pool->free_descr;
 
1277
        while (cur) {
 
1278
                next = cur->next;
 
1279
                cur->pool = NULL;
 
1280
                free_mdl(cur);
 
1281
                cur = next;
 
1282
        }
 
1283
        spin_unlock_bh(&pool->lock);
 
1284
        kfree(pool);
 
1285
        pool = NULL;
 
1286
        EXIT3(return);
 
1287
}
 
1288
 
 
1289
wstdcall void WIN_FUNC(NdisAdjustBufferLength,2)
 
1290
        (ndis_buffer *buffer, UINT length)
 
1291
{
 
1292
        ENTER4("%p, %d", buffer, length);
 
1293
        buffer->bytecount = length;
 
1294
}
 
1295
 
 
1296
wstdcall void WIN_FUNC(NdisQueryBuffer,3)
 
1297
        (ndis_buffer *buffer, void **virt, UINT *length)
 
1298
{
 
1299
        ENTER4("buffer: %p", buffer);
 
1300
        if (virt)
 
1301
                *virt = MmGetSystemAddressForMdl(buffer);
 
1302
        *length = MmGetMdlByteCount(buffer);
 
1303
        TRACE4("%p, %u", virt? *virt : NULL, *length);
 
1304
        return;
 
1305
}
 
1306
 
 
1307
wstdcall void WIN_FUNC(NdisQueryBufferSafe,4)
 
1308
        (ndis_buffer *buffer, void **virt, UINT *length,
 
1309
         enum mm_page_priority priority)
 
1310
{
 
1311
        ENTER4("%p, %p, %p, %d", buffer, virt, length, priority);
 
1312
        if (virt)
 
1313
                *virt = MmGetSystemAddressForMdlSafe(buffer, priority);
 
1314
        *length = MmGetMdlByteCount(buffer);
 
1315
        TRACE4("%p, %u", virt? *virt : NULL, *length);
 
1316
}
 
1317
 
 
1318
wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1)
 
1319
        (ndis_buffer *buffer)
 
1320
{
 
1321
        ENTER3("%p", buffer);
 
1322
        return MmGetSystemAddressForMdl(buffer);
 
1323
}
 
1324
 
 
1325
wstdcall ULONG WIN_FUNC(NdisBufferLength,1)
 
1326
        (ndis_buffer *buffer)
 
1327
{
 
1328
        ENTER3("%p", buffer);
 
1329
        return MmGetMdlByteCount(buffer);
 
1330
}
 
1331
 
 
1332
wstdcall void WIN_FUNC(NdisQueryBufferOffset,3)
 
1333
        (ndis_buffer *buffer, UINT *offset, UINT *length)
 
1334
{
 
1335
        ENTER3("%p", buffer);
 
1336
        *offset = MmGetMdlByteOffset(buffer);
 
1337
        *length = MmGetMdlByteCount(buffer);
 
1338
        TRACE3("%d, %d", *offset, *length);
 
1339
}
 
1340
 
 
1341
wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2)
 
1342
        (struct ndis_packet *packet, ndis_buffer **buffer)
 
1343
{
 
1344
        ndis_buffer *b, *btail;
 
1345
 
 
1346
        ENTER3("%p", packet);
 
1347
        b = packet->private.buffer_head;
 
1348
        if (!b) {
 
1349
                /* no buffer in packet */
 
1350
                *buffer = NULL;
 
1351
                EXIT3(return);
 
1352
        }
 
1353
        btail = packet->private.buffer_tail;
 
1354
        *buffer = btail;
 
1355
        if (b == btail) {
 
1356
                /* one buffer in packet */
 
1357
                packet->private.buffer_head = NULL;
 
1358
                packet->private.buffer_tail = NULL;
 
1359
        } else {
 
1360
                while (b->next != btail)
 
1361
                        b = b->next;
 
1362
                packet->private.buffer_tail = b;
 
1363
                b->next = NULL;
 
1364
        }
 
1365
        packet->private.valid_counts = FALSE;
 
1366
        EXIT3(return);
 
1367
}
 
1368
 
 
1369
wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2)
 
1370
        (struct ndis_packet *packet, ndis_buffer **buffer)
 
1371
{
 
1372
        ENTER3("%p", packet);
 
1373
        if (packet->private.buffer_head == NULL) {
 
1374
                /* no buffer in packet */
 
1375
                *buffer = NULL;
 
1376
                EXIT3(return);
 
1377
        }
 
1378
 
 
1379
        *buffer = packet->private.buffer_head;
 
1380
        if (packet->private.buffer_head == packet->private.buffer_tail) {
 
1381
                /* one buffer in packet */
 
1382
                packet->private.buffer_head = NULL;
 
1383
                packet->private.buffer_tail = NULL;
 
1384
        } else
 
1385
                packet->private.buffer_head = (*buffer)->next;
 
1386
 
 
1387
        packet->private.valid_counts = FALSE;
 
1388
        EXIT3(return);
 
1389
}
 
1390
 
 
1391
wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6)
 
1392
        (struct ndis_packet *packet, ndis_buffer **first_buffer,
 
1393
         void **first_buffer_va, UINT *first_buffer_length,
 
1394
         UINT *total_buffer_length, enum mm_page_priority priority)
 
1395
{
 
1396
        ndis_buffer *b = packet->private.buffer_head;
 
1397
 
 
1398
        ENTER3("%p(%p)", packet, b);
 
1399
        *first_buffer = b;
 
1400
        if (b) {
 
1401
                *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority);
 
1402
                *first_buffer_length = *total_buffer_length =
 
1403
                        MmGetMdlByteCount(b);
 
1404
                for (b = b->next; b; b = b->next)
 
1405
                        *total_buffer_length += MmGetMdlByteCount(b);
 
1406
        } else {
 
1407
                *first_buffer_va = NULL;
 
1408
                *first_buffer_length = 0;
 
1409
                *total_buffer_length = 0;
 
1410
        }
 
1411
        TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length,
 
1412
               *total_buffer_length);
 
1413
        EXIT3(return);
 
1414
}
 
1415
 
 
1416
wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6)
 
1417
        (struct ndis_packet *packet, ndis_buffer **first_buffer,
 
1418
         void **first_buffer_va, UINT *first_buffer_length,
 
1419
         UINT *total_buffer_length, enum mm_page_priority priority)
 
1420
{
 
1421
        NdisGetFirstBufferFromPacketSafe(packet, first_buffer,
 
1422
                                         first_buffer_va, first_buffer_length,
 
1423
                                         total_buffer_length,
 
1424
                                         NormalPagePriority);
 
1425
}
 
1426
 
 
1427
wstdcall void WIN_FUNC(NdisAllocatePacketPoolEx,5)
 
1428
        (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle,
 
1429
         UINT num_descr, UINT overflowsize, UINT proto_rsvd_length)
 
1430
{
 
1431
        struct ndis_packet_pool *pool;
 
1432
 
 
1433
        ENTER3("buffers: %d, length: %d", num_descr, proto_rsvd_length);
 
1434
        pool = kzalloc(sizeof(*pool), irql_gfp());
 
1435
        if (!pool) {
 
1436
                *status = NDIS_STATUS_RESOURCES;
 
1437
                EXIT3(return);
 
1438
        }
 
1439
        spin_lock_init(&pool->lock);
 
1440
        pool->max_descr = num_descr;
 
1441
        pool->num_allocated_descr = 0;
 
1442
        pool->num_used_descr = 0;
 
1443
        pool->free_descr = NULL;
 
1444
        pool->proto_rsvd_length = proto_rsvd_length;
 
1445
        *pool_handle = pool;
 
1446
        *status = NDIS_STATUS_SUCCESS;
 
1447
        TRACE3("pool: %p", pool);
 
1448
        EXIT3(return);
 
1449
}
 
1450
 
 
1451
wstdcall void WIN_FUNC(NdisAllocatePacketPool,4)
 
1452
        (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle,
 
1453
         UINT num_descr, UINT proto_rsvd_length)
 
1454
{
 
1455
        NdisAllocatePacketPoolEx(status, pool_handle, num_descr, 0,
 
1456
                                 proto_rsvd_length);
 
1457
        EXIT3(return);
 
1458
}
 
1459
 
 
1460
wstdcall void WIN_FUNC(NdisFreePacketPool,1)
 
1461
        (struct ndis_packet_pool *pool)
 
1462
{
 
1463
        struct ndis_packet *packet, *next;
 
1464
 
 
1465
        ENTER3("pool: %p", pool);
 
1466
        if (!pool) {
 
1467
                WARNING("invalid pool");
 
1468
                EXIT3(return);
 
1469
        }
 
1470
        spin_lock_bh(&pool->lock);
 
1471
        packet = pool->free_descr;
 
1472
        while (packet) {
 
1473
                next = (struct ndis_packet *)packet->reserved[0];
 
1474
                kfree(packet);
 
1475
                packet = next;
 
1476
        }
 
1477
        pool->num_allocated_descr = 0;
 
1478
        pool->num_used_descr = 0;
 
1479
        pool->free_descr = NULL;
 
1480
        spin_unlock_bh(&pool->lock);
 
1481
        kfree(pool);
 
1482
        EXIT3(return);
 
1483
}
 
1484
 
 
1485
wstdcall UINT WIN_FUNC(NdisPacketPoolUsage,1)
 
1486
        (struct ndis_packet_pool *pool)
 
1487
{
 
1488
        EXIT4(return pool->num_used_descr);
 
1489
}
 
1490
 
 
1491
wstdcall void WIN_FUNC(NdisAllocatePacket,3)
 
1492
        (NDIS_STATUS *status, struct ndis_packet **ndis_packet,
 
1493
         struct ndis_packet_pool *pool)
 
1494
{
 
1495
        struct ndis_packet *packet;
 
1496
        int packet_length;
 
1497
 
 
1498
        ENTER4("pool: %p", pool);
 
1499
        if (!pool) {
 
1500
                *status = NDIS_STATUS_RESOURCES;
 
1501
                *ndis_packet = NULL;
 
1502
                EXIT4(return);
 
1503
        }
 
1504
        assert_irql(_irql_ <= SOFT_LEVEL);
 
1505
        if (pool->num_used_descr > pool->max_descr) {
 
1506
                TRACE3("pool %p is full: %d(%d)", pool,
 
1507
                       pool->num_used_descr, pool->max_descr);
 
1508
#ifndef ALLOW_POOL_OVERFLOW
 
1509
                *status = NDIS_STATUS_RESOURCES;
 
1510
                *ndis_packet = NULL;
 
1511
                return;
 
1512
#endif
 
1513
        }
 
1514
        /* packet has space for 1 byte in protocol_reserved field */
 
1515
        packet_length = sizeof(*packet) - 1 + pool->proto_rsvd_length +
 
1516
                sizeof(struct ndis_packet_oob_data);
 
1517
        spin_lock_bh(&pool->lock);
 
1518
        if ((packet = pool->free_descr))
 
1519
                pool->free_descr = (void *)packet->reserved[0];
 
1520
        spin_unlock_bh(&pool->lock);
 
1521
        if (!packet) {
 
1522
                packet = kmalloc(packet_length, irql_gfp());
 
1523
                if (!packet) {
 
1524
                        WARNING("couldn't allocate packet");
 
1525
                        *status = NDIS_STATUS_RESOURCES;
 
1526
                        *ndis_packet = NULL;
 
1527
                        return;
 
1528
                }
 
1529
                atomic_inc_var(pool->num_allocated_descr);
 
1530
        }
 
1531
        TRACE4("%p, %p", pool, packet);
 
1532
        atomic_inc_var(pool->num_used_descr);
 
1533
        memset(packet, 0, packet_length);
 
1534
        packet->private.oob_offset =
 
1535
                packet_length - sizeof(struct ndis_packet_oob_data);
 
1536
        packet->private.packet_flags = fPACKET_ALLOCATED_BY_NDIS;
 
1537
        packet->private.pool = pool;
 
1538
        *ndis_packet = packet;
 
1539
        *status = NDIS_STATUS_SUCCESS;
 
1540
        EXIT4(return);
 
1541
}
 
1542
 
 
1543
wstdcall void WIN_FUNC(NdisDprAllocatePacket,3)
 
1544
        (NDIS_STATUS *status, struct ndis_packet **packet,
 
1545
         struct ndis_packet_pool *pool)
 
1546
{
 
1547
        NdisAllocatePacket(status, packet, pool);
 
1548
}
 
1549
 
 
1550
wstdcall void WIN_FUNC(NdisFreePacket,1)
 
1551
        (struct ndis_packet *packet)
 
1552
{
 
1553
        struct ndis_packet_pool *pool;
 
1554
 
 
1555
        ENTER4("%p, %p", packet, packet->private.pool);
 
1556
        pool = packet->private.pool;
 
1557
        if (!pool) {
 
1558
                ERROR("invalid pool %p", packet);
 
1559
                EXIT4(return);
 
1560
        }
 
1561
        assert((int)pool->num_used_descr > 0);
 
1562
        atomic_dec_var(pool->num_used_descr);
 
1563
        if (packet->reserved[1]) {
 
1564
                TRACE3("%p, %p", packet, (void *)packet->reserved[1]);
 
1565
                kfree((void *)packet->reserved[1]);
 
1566
                packet->reserved[1] = 0;
 
1567
        }
 
1568
        if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_PACKETS) {
 
1569
                TRACE3("%p", pool);
 
1570
                atomic_dec_var(pool->num_allocated_descr);
 
1571
                kfree(packet);
 
1572
        } else {
 
1573
                TRACE4("%p, %p, %p", pool, packet, pool->free_descr);
 
1574
                spin_lock_bh(&pool->lock);
 
1575
                packet->reserved[0] =
 
1576
                        (typeof(packet->reserved[0]))pool->free_descr;
 
1577
                pool->free_descr = packet;
 
1578
                spin_unlock_bh(&pool->lock);
 
1579
        }
 
1580
        EXIT4(return);
 
1581
}
 
1582
 
 
1583
wstdcall struct ndis_packet_stack *WIN_FUNC(NdisIMGetCurrentPacketStack,2)
 
1584
        (struct ndis_packet *packet, BOOLEAN *stacks_remain)
 
1585
{
 
1586
        struct ndis_packet_stack *stack;
 
1587
 
 
1588
        if (!packet->reserved[1]) {
 
1589
                stack = kzalloc(2 * sizeof(*stack), irql_gfp());
 
1590
                TRACE3("%p, %p", packet, stack);
 
1591
                packet->reserved[1] = (typeof(packet->reserved[1]))stack;
 
1592
        } else {
 
1593
                stack = (void *)packet->reserved[1];;
 
1594
                if (xchg(&stack->ndis_reserved[0], 1)) {
 
1595
                        stack++;
 
1596
                        if (xchg(&stack->ndis_reserved[0], 1))
 
1597
                                stack = NULL;
 
1598
                }
 
1599
                TRACE3("%p", stack);
 
1600
        }
 
1601
        if (stack)
 
1602
                *stacks_remain = TRUE;
 
1603
        else
 
1604
                *stacks_remain = FALSE;
 
1605
 
 
1606
        EXIT3(return stack);
 
1607
}
 
1608
 
 
1609
wstdcall void WIN_FUNC(NdisCopyFromPacketToPacketSafe,7)
 
1610
        (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy,
 
1611
         struct ndis_packet *src, UINT src_offset, UINT *num_copied,
 
1612
         enum mm_page_priority priority)
 
1613
{
 
1614
        UINT dst_n, src_n, n, left;
 
1615
        ndis_buffer *dst_buf;
 
1616
        ndis_buffer *src_buf;
 
1617
 
 
1618
        ENTER4("");
 
1619
        if (!dst || !src) {
 
1620
                *num_copied = 0;
 
1621
                EXIT4(return);
 
1622
        }
 
1623
 
 
1624
        dst_buf = dst->private.buffer_head;
 
1625
        src_buf = src->private.buffer_head;
 
1626
 
 
1627
        if (!dst_buf || !src_buf) {
 
1628
                *num_copied = 0;
 
1629
                EXIT4(return);
 
1630
        }
 
1631
        dst_n = MmGetMdlByteCount(dst_buf) - dst_offset;
 
1632
        src_n = MmGetMdlByteCount(src_buf) - src_offset;
 
1633
 
 
1634
        n = min(src_n, dst_n);
 
1635
        n = min(n, num_to_copy);
 
1636
        memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset,
 
1637
               MmGetSystemAddressForMdl(src_buf) + src_offset, n);
 
1638
 
 
1639
        left = num_to_copy - n;
 
1640
        while (left > 0) {
 
1641
                src_offset += n;
 
1642
                dst_offset += n;
 
1643
                dst_n -= n;
 
1644
                src_n -= n;
 
1645
                if (dst_n == 0) {
 
1646
                        dst_buf = dst_buf->next;
 
1647
                        if (!dst_buf)
 
1648
                                break;
 
1649
                        dst_n = MmGetMdlByteCount(dst_buf);
 
1650
                        dst_offset = 0;
 
1651
                }
 
1652
                if (src_n == 0) {
 
1653
                        src_buf = src_buf->next;
 
1654
                        if (!src_buf)
 
1655
                                break;
 
1656
                        src_n = MmGetMdlByteCount(src_buf);
 
1657
                        src_offset = 0;
 
1658
                }
 
1659
 
 
1660
                n = min(src_n, dst_n);
 
1661
                n = min(n, left);
 
1662
                memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset,
 
1663
                       MmGetSystemAddressForMdl(src_buf) + src_offset, n);
 
1664
                left -= n;
 
1665
        }
 
1666
        *num_copied = num_to_copy - left;
 
1667
        EXIT4(return);
 
1668
}
 
1669
 
 
1670
wstdcall void WIN_FUNC(NdisCopyFromPacketToPacket,6)
 
1671
        (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy,
 
1672
         struct ndis_packet *src, UINT src_offset, UINT *num_copied)
 
1673
{
 
1674
        NdisCopyFromPacketToPacketSafe(dst, dst_offset, num_to_copy,
 
1675
                                       src, src_offset, num_copied,
 
1676
                                       NormalPagePriority);
 
1677
        return;
 
1678
}
 
1679
 
 
1680
wstdcall void WIN_FUNC(NdisIMCopySendPerPacketInfo,2)
 
1681
        (struct ndis_packet *dst, struct ndis_packet *src)
 
1682
{
 
1683
        struct ndis_packet_oob_data *dst_oob, *src_oob;
 
1684
        dst_oob = NDIS_PACKET_OOB_DATA(dst);
 
1685
        src_oob = NDIS_PACKET_OOB_DATA(src);
 
1686
        memcpy(&dst_oob->ext, &src_oob->ext, sizeof(dst_oob->ext));
 
1687
        return;
 
1688
}
 
1689
 
 
1690
wstdcall void WIN_FUNC(NdisSend,3)
 
1691
        (NDIS_STATUS *status, struct ndis_mp_block *nmb,
 
1692
         struct ndis_packet *packet)
 
1693
{
 
1694
        struct ndis_device *wnd = nmb->wnd;
 
1695
        struct miniport *mp;
 
1696
        KIRQL irql;
 
1697
 
 
1698
        mp = &wnd->wd->driver->ndis_driver->mp;
 
1699
        if (mp->send_packets) {
 
1700
                irql = serialize_lock_irql(wnd);
 
1701
                assert_irql(_irql_ == DISPATCH_LEVEL);
 
1702
                LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, &packet, 1);
 
1703
                serialize_unlock_irql(wnd, irql);
 
1704
                if (deserialized_driver(wnd))
 
1705
                        *status = NDIS_STATUS_PENDING;
 
1706
                else {
 
1707
                        struct ndis_packet_oob_data *oob_data;
 
1708
                        oob_data = NDIS_PACKET_OOB_DATA(packet);
 
1709
                        *status = oob_data->status;
 
1710
                        switch (*status) {
 
1711
                        case NDIS_STATUS_SUCCESS:
 
1712
                                free_tx_packet(wnd, packet, *status);
 
1713
                                break;
 
1714
                        case NDIS_STATUS_PENDING:
 
1715
                                break;
 
1716
                        case NDIS_STATUS_RESOURCES:
 
1717
                                wnd->tx_ok = 0;
 
1718
                                break;
 
1719
                        case NDIS_STATUS_FAILURE:
 
1720
                        default:
 
1721
                                free_tx_packet(wnd, packet, *status);
 
1722
                                break;
 
1723
                        }
 
1724
                }
 
1725
        } else {
 
1726
                irql = serialize_lock_irql(wnd);
 
1727
                assert_irql(_irql_ == DISPATCH_LEVEL);
 
1728
                *status = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, packet, 0);
 
1729
                serialize_unlock_irql(wnd, irql);
 
1730
                switch (*status) {
 
1731
                case NDIS_STATUS_SUCCESS:
 
1732
                        free_tx_packet(wnd, packet, *status);
 
1733
                        break;
 
1734
                case NDIS_STATUS_PENDING:
 
1735
                        break;
 
1736
                case NDIS_STATUS_RESOURCES:
 
1737
                        wnd->tx_ok = 0;
 
1738
                        break;
 
1739
                case NDIS_STATUS_FAILURE:
 
1740
                default:
 
1741
                        free_tx_packet(wnd, packet, *status);
 
1742
                        break;
 
1743
                }
 
1744
        }
 
1745
        EXIT3(return);
 
1746
}
 
1747
 
 
1748
/* called for serialized drivers only */
 
1749
wstdcall void mp_timer_dpc(struct kdpc *kdpc, void *ctx, void *arg1, void *arg2)
 
1750
{
 
1751
        struct ndis_mp_timer *timer;
 
1752
        struct ndis_mp_block *nmb;
 
1753
 
 
1754
        timer = ctx;
 
1755
        TIMERENTER("%p, %p, %p, %p", timer, timer->func, timer->ctx, timer->nmb);
 
1756
        assert_irql(_irql_ == DISPATCH_LEVEL);
 
1757
        nmb = timer->nmb;
 
1758
        serialize_lock(nmb->wnd);
 
1759
        LIN2WIN4(timer->func, NULL, timer->ctx, NULL, NULL);
 
1760
        serialize_unlock(nmb->wnd);
 
1761
        TIMEREXIT(return);
 
1762
}
 
1763
WIN_FUNC_DECL(mp_timer_dpc,4)
 
1764
 
 
1765
wstdcall void WIN_FUNC(NdisMInitializeTimer,4)
 
1766
        (struct ndis_mp_timer *timer, struct ndis_mp_block *nmb,
 
1767
         DPC func, void *ctx)
 
1768
{
 
1769
        TIMERENTER("%p, %p, %p, %p", timer, func, ctx, nmb);
 
1770
        assert_irql(_irql_ == PASSIVE_LEVEL);
 
1771
        timer->func = func;
 
1772
        timer->ctx = ctx;
 
1773
        timer->nmb = nmb;
 
1774
        if (deserialized_driver(nmb->wnd))
 
1775
                KeInitializeDpc(&timer->kdpc, func, ctx);
 
1776
        else
 
1777
                KeInitializeDpc(&timer->kdpc, WIN_FUNC_PTR(mp_timer_dpc,4),
 
1778
                                timer);
 
1779
        wrap_init_timer(&timer->nt_timer, NotificationTimer, nmb);
 
1780
        TIMEREXIT(return);
 
1781
}
 
1782
 
 
1783
wstdcall void WIN_FUNC(NdisMSetPeriodicTimer,2)
 
1784
        (struct ndis_mp_timer *timer, UINT period_ms)
 
1785
{
 
1786
        unsigned long expires = MSEC_TO_HZ(period_ms);
 
1787
 
 
1788
        TIMERENTER("%p, %u, %ld", timer, period_ms, expires);
 
1789
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
1790
        wrap_set_timer(&timer->nt_timer, expires, expires, &timer->kdpc);
 
1791
        TIMEREXIT(return);
 
1792
}
 
1793
 
 
1794
wstdcall void WIN_FUNC(NdisMCancelTimer,2)
 
1795
        (struct ndis_mp_timer *timer, BOOLEAN *canceled)
 
1796
{
 
1797
        TIMERENTER("%p", timer);
 
1798
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
1799
        *canceled = KeCancelTimer(&timer->nt_timer);
 
1800
        TIMERTRACE("%d", *canceled);
 
1801
        return;
 
1802
}
 
1803
 
 
1804
wstdcall void WIN_FUNC(NdisInitializeTimer,3)
 
1805
        (struct ndis_timer *timer, void *func, void *ctx)
 
1806
{
 
1807
        TIMERENTER("%p, %p, %p", timer, func, ctx);
 
1808
        assert_irql(_irql_ == PASSIVE_LEVEL);
 
1809
        KeInitializeDpc(&timer->kdpc, func, ctx);
 
1810
        wrap_init_timer(&timer->nt_timer, NotificationTimer, NULL);
 
1811
        TIMEREXIT(return);
 
1812
}
 
1813
 
 
1814
/* NdisMSetTimer is a macro that calls NdisSetTimer with
 
1815
 * ndis_mp_timer typecast to ndis_timer */
 
1816
 
 
1817
wstdcall void WIN_FUNC(NdisSetTimer,2)
 
1818
        (struct ndis_timer *timer, UINT duetime_ms)
 
1819
{
 
1820
        unsigned long expires = MSEC_TO_HZ(duetime_ms);
 
1821
 
 
1822
        TIMERENTER("%p, %p, %u, %ld", timer, timer->nt_timer.wrap_timer,
 
1823
                   duetime_ms, expires);
 
1824
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
1825
        wrap_set_timer(&timer->nt_timer, expires, 0, &timer->kdpc);
 
1826
        TIMEREXIT(return);
 
1827
}
 
1828
 
 
1829
wstdcall void WIN_FUNC(NdisCancelTimer,2)
 
1830
        (struct ndis_timer *timer, BOOLEAN *canceled)
 
1831
{
 
1832
        TIMERENTER("%p", timer);
 
1833
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
1834
        *canceled = KeCancelTimer(&timer->nt_timer);
 
1835
        TIMEREXIT(return);
 
1836
}
 
1837
 
 
1838
wstdcall void WIN_FUNC(NdisMRegisterAdapterShutdownHandler,3)
 
1839
        (struct ndis_mp_block *nmb, void *ctx, void *func)
 
1840
{
 
1841
        struct ndis_device *wnd = nmb->wnd;
 
1842
        ENTER1("%p", func);
 
1843
        wnd->wd->driver->ndis_driver->mp.shutdown = func;
 
1844
        wnd->shutdown_ctx = ctx;
 
1845
}
 
1846
 
 
1847
wstdcall void WIN_FUNC(NdisMDeregisterAdapterShutdownHandler,1)
 
1848
        (struct ndis_mp_block *nmb)
 
1849
{
 
1850
        struct ndis_device *wnd = nmb->wnd;
 
1851
        wnd->wd->driver->ndis_driver->mp.shutdown = NULL;
 
1852
        wnd->shutdown_ctx = NULL;
 
1853
}
 
1854
 
 
1855
/* TODO: rt61 (serialized) driver doesn't want MiniportEnableInterrupt
 
1856
 * to be called in irq handler, but mrv800c (deserialized) driver
 
1857
 * wants. NDIS is confusing about when to call MiniportEnableInterrupt
 
1858
 * For now, handle these cases with two separate irq handlers based on
 
1859
 * observation of these two drivers. However, it is likely not
 
1860
 * correct. */
 
1861
wstdcall void deserialized_irq_handler(struct kdpc *kdpc, void *ctx,
 
1862
                                       void *arg1, void *arg2)
 
1863
{
 
1864
        struct ndis_device *wnd = ctx;
 
1865
        ndis_interrupt_handler irq_handler = arg1;
 
1866
        struct miniport *mp = arg2;
 
1867
 
 
1868
        TRACE6("%p", irq_handler);
 
1869
        assert_irql(_irql_ == DISPATCH_LEVEL);
 
1870
        LIN2WIN1(irq_handler, wnd->nmb->mp_ctx);
 
1871
        if (mp->enable_interrupt)
 
1872
                LIN2WIN1(mp->enable_interrupt, wnd->nmb->mp_ctx);
 
1873
        EXIT6(return);
 
1874
}
 
1875
WIN_FUNC_DECL(deserialized_irq_handler,4)
 
1876
 
 
1877
wstdcall void serialized_irq_handler(struct kdpc *kdpc, void *ctx,
 
1878
                                     void *arg1, void *arg2)
 
1879
{
 
1880
        struct ndis_device *wnd = ctx;
 
1881
        ndis_interrupt_handler irq_handler = arg1;
 
1882
 
 
1883
        TRACE6("%p, %p, %p", wnd, irq_handler, arg2);
 
1884
        assert_irql(_irql_ == DISPATCH_LEVEL);
 
1885
        serialize_lock(wnd);
 
1886
        LIN2WIN1(irq_handler, arg2);
 
1887
        serialize_unlock(wnd);
 
1888
        EXIT6(return);
 
1889
}
 
1890
WIN_FUNC_DECL(serialized_irq_handler,4)
 
1891
 
 
1892
wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx)
 
1893
{
 
1894
        struct ndis_mp_interrupt *mp_interrupt = ctx;
 
1895
        struct ndis_device *wnd = mp_interrupt->nmb->wnd;
 
1896
        BOOLEAN recognized = TRUE, queue_handler = TRUE;
 
1897
 
 
1898
        TRACE6("%p", wnd);
 
1899
        /* kernel may call ISR when registering interrupt, in
 
1900
         * the same context if DEBUG_SHIRQ is enabled */
 
1901
        assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL);
 
1902
        if (mp_interrupt->shared)
 
1903
                LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler,
 
1904
                         wnd->nmb->mp_ctx);
 
1905
        else {
 
1906
                struct miniport *mp;
 
1907
                mp = &wnd->wd->driver->ndis_driver->mp;
 
1908
                LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx);
 
1909
                /* it is not shared interrupt, so handler must be called */
 
1910
                recognized = queue_handler = TRUE;
 
1911
        }
 
1912
        if (recognized) {
 
1913
                if (queue_handler) {
 
1914
                        TRACE5("%p", &wnd->irq_kdpc);
 
1915
                        queue_kdpc(&wnd->irq_kdpc);
 
1916
                }
 
1917
                EXIT6(return TRUE);
 
1918
        }
 
1919
        EXIT6(return FALSE);
 
1920
}
 
1921
WIN_FUNC_DECL(ndis_isr,2)
 
1922
 
 
1923
wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7)
 
1924
        (struct ndis_mp_interrupt *mp_interrupt,
 
1925
         struct ndis_mp_block *nmb, UINT vector, UINT level,
 
1926
         BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode)
 
1927
{
 
1928
        struct ndis_device *wnd = nmb->wnd;
 
1929
        struct miniport *mp;
 
1930
 
 
1931
        ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d",
 
1932
               mp_interrupt, vector, level, req_isr, shared, mode);
 
1933
 
 
1934
        mp = &wnd->wd->driver->ndis_driver->mp;
 
1935
        nt_spin_lock_init(&mp_interrupt->lock);
 
1936
        mp_interrupt->irq = vector;
 
1937
        mp_interrupt->isr = mp->isr;
 
1938
        mp_interrupt->mp_dpc = mp->handle_interrupt;
 
1939
        mp_interrupt->nmb = nmb;
 
1940
        mp_interrupt->req_isr = req_isr;
 
1941
        if (shared && !req_isr)
 
1942
                WARNING("shared but dynamic interrupt!");
 
1943
        mp_interrupt->shared = shared;
 
1944
        wnd->mp_interrupt = mp_interrupt;
 
1945
        if (mp->enable_interrupt)
 
1946
                mp_interrupt->enable = TRUE;
 
1947
        else
 
1948
                mp_interrupt->enable = FALSE;
 
1949
 
 
1950
        if (deserialized_driver(wnd)) {
 
1951
                KeInitializeDpc(&wnd->irq_kdpc,
 
1952
                                WIN_FUNC_PTR(deserialized_irq_handler,4),
 
1953
                                nmb->wnd);
 
1954
                wnd->irq_kdpc.arg1 = mp->handle_interrupt;
 
1955
                wnd->irq_kdpc.arg2 = mp;
 
1956
                TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2,
 
1957
                       nmb->wnd, nmb->mp_ctx);
 
1958
        } else {
 
1959
                KeInitializeDpc(&wnd->irq_kdpc,
 
1960
                                WIN_FUNC_PTR(serialized_irq_handler,4),
 
1961
                                nmb->wnd);
 
1962
                wnd->irq_kdpc.arg1 = mp->handle_interrupt;
 
1963
                wnd->irq_kdpc.arg2 = nmb->mp_ctx;
 
1964
                TRACE2("%p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2,
 
1965
                       nmb->wnd);
 
1966
        }
 
1967
 
 
1968
        if (IoConnectInterrupt(&mp_interrupt->kinterrupt,
 
1969
                               WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL,
 
1970
                               vector, DIRQL, DIRQL, mode, shared, 0, FALSE) !=
 
1971
            STATUS_SUCCESS) {
 
1972
                printk(KERN_WARNING "%s: request for IRQ %d failed\n",
 
1973
                       DRIVER_NAME, vector);
 
1974
                return NDIS_STATUS_RESOURCES;
 
1975
        }
 
1976
        printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector);
 
1977
        EXIT1(return NDIS_STATUS_SUCCESS);
 
1978
}
 
1979
 
 
1980
wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1)
 
1981
        (struct ndis_mp_interrupt *mp_interrupt)
 
1982
{
 
1983
        struct ndis_mp_block *nmb;
 
1984
 
 
1985
        ENTER1("%p", mp_interrupt);
 
1986
        nmb = xchg(&mp_interrupt->nmb, NULL);
 
1987
        TRACE1("%p", nmb);
 
1988
        if (!nmb) {
 
1989
                WARNING("interrupt already freed?");
 
1990
                return;
 
1991
        }
 
1992
        nmb->wnd->mp_interrupt = NULL;
 
1993
        if (dequeue_kdpc(&nmb->wnd->irq_kdpc))
 
1994
                TRACE2("interrupt kdpc was pending");
 
1995
        flush_workqueue(wrapndis_wq);
 
1996
        IoDisconnectInterrupt(mp_interrupt->kinterrupt);
 
1997
        EXIT1(return);
 
1998
}
 
1999
 
 
2000
wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3)
 
2001
        (struct ndis_mp_interrupt *mp_interrupt,
 
2002
         PKSYNCHRONIZE_ROUTINE sync_func, void *ctx)
 
2003
{
 
2004
        return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx);
 
2005
}
 
2006
 
 
2007
/* called via function pointer; but 64-bit RNDIS driver calls directly */
 
2008
wstdcall void WIN_FUNC(NdisMIndicateStatus,4)
 
2009
        (struct ndis_mp_block *nmb, NDIS_STATUS status, void *buf, UINT len)
 
2010
{
 
2011
        struct ndis_device *wnd = nmb->wnd;
 
2012
        struct ndis_status_indication *si;
 
2013
 
 
2014
        ENTER2("status=0x%x len=%d", status, len);
 
2015
        switch (status) {
 
2016
        case NDIS_STATUS_MEDIA_CONNECT:
 
2017
                set_media_state(wnd, NdisMediaStateConnected);
 
2018
                break;
 
2019
        case NDIS_STATUS_MEDIA_DISCONNECT:
 
2020
                set_media_state(wnd, NdisMediaStateDisconnected);
 
2021
                break;
 
2022
        case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION:
 
2023
                if (!buf)
 
2024
                        break;
 
2025
                si = buf;
 
2026
                TRACE2("status_type=%d", si->status_type);
 
2027
                switch (si->status_type) {
 
2028
                case Ndis802_11StatusType_MediaStreamMode:
 
2029
                        break;
 
2030
#ifdef CONFIG_WIRELESS_EXT
 
2031
                case Ndis802_11StatusType_Authentication:
 
2032
                        buf = (char *)buf + sizeof(*si);
 
2033
                        len -= sizeof(*si);
 
2034
                        while (len > 0) {
 
2035
                                int pairwise_error = 0, group_error = 0;
 
2036
                                struct ndis_auth_req *auth_req =
 
2037
                                        (struct ndis_auth_req *)buf;
 
2038
                                TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid));
 
2039
                                if (auth_req->flags & 0x01)
 
2040
                                        TRACE2("reauth request");
 
2041
                                if (auth_req->flags & 0x02)
 
2042
                                        TRACE2("key update request");
 
2043
                                if (auth_req->flags & 0x06) {
 
2044
                                        pairwise_error = 1;
 
2045
                                        TRACE2("pairwise_error");
 
2046
                                }
 
2047
                                if (auth_req->flags & 0x0E) {
 
2048
                                        group_error = 1;
 
2049
                                        TRACE2("group_error");
 
2050
                                }
 
2051
                                if (pairwise_error || group_error) {
 
2052
                                        union iwreq_data wrqu;
 
2053
                                        struct iw_michaelmicfailure micfailure;
 
2054
 
 
2055
                                        memset(&micfailure, 0, sizeof(micfailure));
 
2056
                                        if (pairwise_error)
 
2057
                                                micfailure.flags |=
 
2058
                                                        IW_MICFAILURE_PAIRWISE;
 
2059
                                        if (group_error)
 
2060
                                                micfailure.flags |=
 
2061
                                                        IW_MICFAILURE_GROUP;
 
2062
                                        memcpy(micfailure.src_addr.sa_data,
 
2063
                                               auth_req->bssid, ETH_ALEN);
 
2064
                                        memset(&wrqu, 0, sizeof(wrqu));
 
2065
                                        wrqu.data.length = sizeof(micfailure);
 
2066
                                        wireless_send_event(wnd->net_dev,
 
2067
                                                            IWEVMICHAELMICFAILURE,
 
2068
                                                            &wrqu, (u8 *)&micfailure);
 
2069
                                }
 
2070
                                len -= auth_req->length;
 
2071
                                buf = (char *)buf + auth_req->length;
 
2072
                        }
 
2073
                        break;
 
2074
                case Ndis802_11StatusType_PMKID_CandidateList:
 
2075
                {
 
2076
                        u8 *end;
 
2077
                        unsigned long i;
 
2078
                        struct ndis_pmkid_candidate_list *cand;
 
2079
 
 
2080
                        cand = buf + sizeof(struct ndis_status_indication);
 
2081
                        if (len < sizeof(struct ndis_status_indication) +
 
2082
                            sizeof(struct ndis_pmkid_candidate_list) ||
 
2083
                                cand->version != 1) {
 
2084
                                WARNING("unrecognized PMKID ignored");
 
2085
                                EXIT1(return);
 
2086
                        }
 
2087
 
 
2088
                        end = (u8 *)buf + len;
 
2089
                        TRACE2("PMKID ver %d num_cand %d",
 
2090
                               cand->version, cand->num_candidates);
 
2091
                        for (i = 0; i < cand->num_candidates; i++) {
 
2092
                                struct iw_pmkid_cand pcand;
 
2093
                                union iwreq_data wrqu;
 
2094
                                struct ndis_pmkid_candidate *c =
 
2095
                                        &cand->candidates[i];
 
2096
                                if ((u8 *)(c + 1) > end) {
 
2097
                                        TRACE2("truncated PMKID");
 
2098
                                        break;
 
2099
                                }
 
2100
                                TRACE2("%ld: " MACSTRSEP " 0x%x",
 
2101
                                       i, MAC2STR(c->bssid), c->flags);
 
2102
                                memset(&pcand, 0, sizeof(pcand));
 
2103
                                if (c->flags & 0x01)
 
2104
                                        pcand.flags |= IW_PMKID_CAND_PREAUTH;
 
2105
                                pcand.index = i;
 
2106
                                memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN);
 
2107
 
 
2108
                                memset(&wrqu, 0, sizeof(wrqu));
 
2109
                                wrqu.data.length = sizeof(pcand);
 
2110
                                wireless_send_event(wnd->net_dev, IWEVPMKIDCAND,
 
2111
                                                    &wrqu, (u8 *)&pcand);
 
2112
                        }
 
2113
                        break;
 
2114
                }
 
2115
                case Ndis802_11StatusType_RadioState:
 
2116
                {
 
2117
                        struct ndis_radio_status_indication *radio_status = buf;
 
2118
                        if (radio_status->radio_state ==
 
2119
                            Ndis802_11RadioStatusOn)
 
2120
                                INFO("radio is turned on");
 
2121
                        else if (radio_status->radio_state ==
 
2122
                                 Ndis802_11RadioStatusHardwareOff)
 
2123
                                INFO("radio is turned off by hardware");
 
2124
                        else if (radio_status->radio_state ==
 
2125
                                 Ndis802_11RadioStatusSoftwareOff)
 
2126
                                INFO("radio is turned off by software");
 
2127
                        break;
 
2128
                }
 
2129
#endif
 
2130
                default:
 
2131
                        /* is this RSSI indication? */
 
2132
                        TRACE2("unknown indication: %x", si->status_type);
 
2133
                        break;
 
2134
                }
 
2135
                break;
 
2136
        default:
 
2137
                TRACE2("unknown status: %08X", status);
 
2138
                break;
 
2139
        }
 
2140
 
 
2141
        EXIT2(return);
 
2142
}
 
2143
 
 
2144
/* called via function pointer; but 64-bit RNDIS driver calls directly */
 
2145
wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1)
 
2146
        (struct ndis_mp_block *nmb)
 
2147
{
 
2148
        struct ndis_device *wnd = nmb->wnd;
 
2149
        ENTER2("%p", wnd);
 
2150
        if (wnd->tx_ok)
 
2151
                schedule_wrapndis_work(&wnd->tx_work);
 
2152
}
 
2153
 
 
2154
/* called via function pointer */
 
2155
wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb,
 
2156
                                struct ndis_packet *packet, NDIS_STATUS status)
 
2157
{
 
2158
        struct ndis_device *wnd = nmb->wnd;
 
2159
        ENTER4("%p, %08X", packet, status);
 
2160
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
2161
        if (deserialized_driver(wnd))
 
2162
                free_tx_packet(wnd, packet, status);
 
2163
        else {
 
2164
                struct ndis_packet_oob_data *oob_data;
 
2165
                NDIS_STATUS pkt_status;
 
2166
                TRACE3("%p, %08x", packet, status);
 
2167
                oob_data = NDIS_PACKET_OOB_DATA(packet);
 
2168
                switch ((pkt_status = xchg(&oob_data->status, status))) {
 
2169
                case NDIS_STATUS_NOT_RECOGNIZED:
 
2170
                        free_tx_packet(wnd, packet, status);
 
2171
                        break;
 
2172
                case NDIS_STATUS_PENDING:
 
2173
                case 0:
 
2174
                        break;
 
2175
                default:
 
2176
                        WARNING("%p: invalid status: %08X", packet, pkt_status);
 
2177
                        break;
 
2178
                }
 
2179
                /* In case a serialized driver has earlier requested a
 
2180
                 * pause by returning NDIS_STATUS_RESOURCES during
 
2181
                 * MiniportSend(Packets), wakeup tx worker now.
 
2182
                 */
 
2183
                if (xchg(&wnd->tx_ok, 1) == 0) {
 
2184
                        TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
 
2185
                        schedule_wrapndis_work(&wnd->tx_work);
 
2186
                }
 
2187
        }
 
2188
        EXIT3(return);
 
2189
}
 
2190
 
 
2191
/* called via function pointer */
 
2192
wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb)
 
2193
{
 
2194
        struct ndis_device *wnd = nmb->wnd;
 
2195
        ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
 
2196
        wnd->tx_ok = 1;
 
2197
        schedule_wrapndis_work(&wnd->tx_work);
 
2198
        EXIT3(return);
 
2199
}
 
2200
 
 
2201
wstdcall void return_packet(void *arg1, void *arg2)
 
2202
{
 
2203
        struct ndis_device *wnd;
 
2204
        struct ndis_packet *packet;
 
2205
        struct miniport *mp;
 
2206
        KIRQL irql;
 
2207
 
 
2208
        wnd = arg1;
 
2209
        packet = arg2;
 
2210
        ENTER4("%p, %p", wnd, packet);
 
2211
        mp = &wnd->wd->driver->ndis_driver->mp;
 
2212
        irql = serialize_lock_irql(wnd);
 
2213
        assert_irql(_irql_ == DISPATCH_LEVEL);
 
2214
        LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet);
 
2215
        serialize_unlock_irql(wnd, irql);
 
2216
        EXIT4(return);
 
2217
}
 
2218
WIN_FUNC_DECL(return_packet,2)
 
2219
 
 
2220
/* called via function pointer */
 
2221
wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb,
 
2222
                                         struct ndis_packet **packets,
 
2223
                                         UINT nr_packets)
 
2224
{
 
2225
        struct ndis_device *wnd;
 
2226
        ndis_buffer *buffer;
 
2227
        struct ndis_packet *packet;
 
2228
        struct sk_buff *skb;
 
2229
        ULONG i, length, total_length;
 
2230
        struct ndis_packet_oob_data *oob_data;
 
2231
        void *virt;
 
2232
        struct ndis_tcp_ip_checksum_packet_info csum;
 
2233
 
 
2234
        ENTER3("%p, %d", nmb, nr_packets);
 
2235
        assert_irql(_irql_ <= DISPATCH_LEVEL);
 
2236
        wnd = nmb->wnd;
 
2237
        for (i = 0; i < nr_packets; i++) {
 
2238
                packet = packets[i];
 
2239
                if (!packet) {
 
2240
                        WARNING("empty packet ignored");
 
2241
                        continue;
 
2242
                }
 
2243
                wnd->net_dev->last_rx = jiffies;
 
2244
                /* get total number of bytes in packet */
 
2245
                NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt,
 
2246
                                                 &length, &total_length,
 
2247
                                                 NormalPagePriority);
 
2248
                TRACE3("%d, %d", length, total_length);
 
2249
                oob_data = NDIS_PACKET_OOB_DATA(packet);
 
2250
                TRACE3("0x%x, 0x%x, %Lu", packet->private.flags,
 
2251
                       packet->private.packet_flags, oob_data->time_rxed);
 
2252
                skb = dev_alloc_skb(total_length);
 
2253
                if (skb) {
 
2254
                        while (buffer) {
 
2255
                                memcpy_skb(skb, MmGetSystemAddressForMdl(buffer),
 
2256
                                           MmGetMdlByteCount(buffer));
 
2257
                                buffer = buffer->next;
 
2258
                        }
 
2259
                        skb->dev = wnd->net_dev;
 
2260
                        skb->protocol = eth_type_trans(skb, wnd->net_dev);
 
2261
                        pre_atomic_add(wnd->net_stats.rx_bytes, total_length);
 
2262
                        atomic_inc_var(wnd->net_stats.rx_packets);
 
2263
                        csum.value = (typeof(csum.value))(ULONG_PTR)
 
2264
                                oob_data->ext.info[TcpIpChecksumPacketInfo];
 
2265
                        TRACE3("0x%05x", csum.value);
 
2266
                        if (wnd->rx_csum.value &&
 
2267
                            (csum.rx.tcp_succeeded || csum.rx.udp_succeeded ||
 
2268
                             csum.rx.ip_succeeded))
 
2269
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
2270
                        else
 
2271
                                skb->ip_summed = CHECKSUM_NONE;
 
2272
 
 
2273
                        if (in_interrupt())
 
2274
                                netif_rx(skb);
 
2275
                        else
 
2276
                                netif_rx_ni(skb);
 
2277
                } else {
 
2278
                        WARNING("couldn't allocate skb; packet dropped");
 
2279
                        atomic_inc_var(wnd->net_stats.rx_dropped);
 
2280
                }
 
2281
 
 
2282
                /* serialized drivers check the status upon return
 
2283
                 * from this function */
 
2284
                if (!deserialized_driver(wnd)) {
 
2285
                        oob_data->status = NDIS_STATUS_SUCCESS;
 
2286
                        continue;
 
2287
                }
 
2288
 
 
2289
                /* if a deserialized driver sets
 
2290
                 * NDIS_STATUS_RESOURCES, then it reclaims the packet
 
2291
                 * upon return from this function */
 
2292
                if (oob_data->status == NDIS_STATUS_RESOURCES)
 
2293
                        continue;
 
2294
 
 
2295
                assert(oob_data->status == NDIS_STATUS_SUCCESS);
 
2296
                /* deserialized driver doesn't check the status upon
 
2297
                 * return from this function; we need to call
 
2298
                 * MiniportReturnPacket later for this packet. Calling
 
2299
                 * MiniportReturnPacket from here is not correct - the
 
2300
                 * driver doesn't expect it (at least Centrino driver
 
2301
                 * crashes) */
 
2302
                schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2),
 
2303
                                        wnd, packet);
 
2304
        }
 
2305
        EXIT3(return);
 
2306
}
 
2307
 
 
2308
/* called via function pointer (by NdisMEthIndicateReceive macro); the
 
2309
 * first argument is nmb->eth_db */
 
2310
wstdcall void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx,
 
2311
                                   char *header1, char *header, UINT header_size,
 
2312
                                   void *look_ahead, UINT look_ahead_size,
 
2313
                                   UINT packet_size)
 
2314
{
 
2315
        struct sk_buff *skb = NULL;
 
2316
        struct ndis_device *wnd;
 
2317
        unsigned int skb_size = 0;
 
2318
        KIRQL irql;
 
2319
        struct ndis_packet_oob_data *oob_data;
 
2320
 
 
2321
        ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, "
 
2322
               "size = %d, packet = %d", nmb, rx_ctx, header, header_size,
 
2323
               look_ahead, look_ahead_size, packet_size);
 
2324
 
 
2325
        wnd = nmb->wnd;
 
2326
        TRACE3("wnd = %p", wnd);
 
2327
        if (!wnd) {
 
2328
                ERROR("nmb is NULL");
 
2329
                EXIT3(return);
 
2330
        }
 
2331
        wnd->net_dev->last_rx = jiffies;
 
2332
 
 
2333
        if (look_ahead_size < packet_size) {
 
2334
                struct ndis_packet *packet;
 
2335
                struct miniport *mp;
 
2336
                unsigned int bytes_txed;
 
2337
                NDIS_STATUS res;
 
2338
 
 
2339
                NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool);
 
2340
                if (res != NDIS_STATUS_SUCCESS) {
 
2341
                        atomic_inc_var(wnd->net_stats.rx_dropped);
 
2342
                        EXIT3(return);
 
2343
                }
 
2344
                oob_data = NDIS_PACKET_OOB_DATA(packet);
 
2345
                mp = &wnd->wd->driver->ndis_driver->mp;
 
2346
                irql = serialize_lock_irql(wnd);
 
2347
                assert_irql(_irql_ == DISPATCH_LEVEL);
 
2348
                res = LIN2WIN6(mp->tx_data, packet, &bytes_txed, nmb,
 
2349
                               rx_ctx, look_ahead_size, packet_size);
 
2350
                serialize_unlock_irql(wnd, irql);
 
2351
                TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed);
 
2352
                if (res == NDIS_STATUS_SUCCESS) {
 
2353
                        ndis_buffer *buffer;
 
2354
                        struct ndis_tcp_ip_checksum_packet_info csum;
 
2355
                        skb = dev_alloc_skb(header_size + look_ahead_size +
 
2356
                                            bytes_txed);
 
2357
                        if (!skb) {
 
2358
                                ERROR("couldn't allocate skb; packet dropped");
 
2359
                                atomic_inc_var(wnd->net_stats.rx_dropped);
 
2360
                                NdisFreePacket(packet);
 
2361
                                return;
 
2362
                        }
 
2363
                        memcpy_skb(skb, header, header_size);
 
2364
                        memcpy_skb(skb, look_ahead, look_ahead_size);
 
2365
                        buffer = packet->private.buffer_head;
 
2366
                        while (buffer) {
 
2367
                                memcpy_skb(skb,
 
2368
                                           MmGetSystemAddressForMdl(buffer),
 
2369
                                           MmGetMdlByteCount(buffer));
 
2370
                                buffer = buffer->next;
 
2371
                        }
 
2372
                        skb_size = header_size + look_ahead_size + bytes_txed;
 
2373
                        csum.value = (typeof(csum.value))(ULONG_PTR)
 
2374
                                oob_data->ext.info[TcpIpChecksumPacketInfo];
 
2375
                        TRACE3("0x%05x", csum.value);
 
2376
                        if (wnd->rx_csum.value &&
 
2377
                            (csum.rx.tcp_succeeded || csum.rx.udp_succeeded))
 
2378
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
2379
                        else
 
2380
                                skb->ip_summed = CHECKSUM_NONE;
 
2381
                        NdisFreePacket(packet);
 
2382
                } else if (res == NDIS_STATUS_PENDING) {
 
2383
                        /* driver will call td_complete */
 
2384
                        oob_data->look_ahead = kmalloc(look_ahead_size,
 
2385
                                                       GFP_ATOMIC);
 
2386
                        if (!oob_data->look_ahead) {
 
2387
                                NdisFreePacket(packet);
 
2388
                                ERROR("packet dropped");
 
2389
                                atomic_inc_var(wnd->net_stats.rx_dropped);
 
2390
                                EXIT3(return);
 
2391
                        }
 
2392
                        assert(sizeof(oob_data->header) == header_size);
 
2393
                        memcpy(oob_data->header, header,
 
2394
                               sizeof(oob_data->header));
 
2395
                        memcpy(oob_data->look_ahead, look_ahead,
 
2396
                               look_ahead_size);
 
2397
                        oob_data->look_ahead_size = look_ahead_size;
 
2398
                        EXIT3(return);
 
2399
                } else {
 
2400
                        WARNING("packet dropped: %08X", res);
 
2401
                        atomic_inc_var(wnd->net_stats.rx_dropped);
 
2402
                        NdisFreePacket(packet);
 
2403
                        EXIT3(return);
 
2404
                }
 
2405
        } else {
 
2406
                skb_size = header_size + packet_size;
 
2407
                skb = dev_alloc_skb(skb_size);
 
2408
                if (skb) {
 
2409
                        memcpy_skb(skb, header, header_size);
 
2410
                        memcpy_skb(skb, look_ahead, packet_size);
 
2411
                }
 
2412
        }
 
2413
 
 
2414
        if (skb) {
 
2415
                skb->dev = wnd->net_dev;
 
2416
                skb->protocol = eth_type_trans(skb, wnd->net_dev);
 
2417
                pre_atomic_add(wnd->net_stats.rx_bytes, skb_size);
 
2418
                atomic_inc_var(wnd->net_stats.rx_packets);
 
2419
                if (in_interrupt())
 
2420
                        netif_rx(skb);
 
2421
                else
 
2422
                        netif_rx_ni(skb);
 
2423
        }
 
2424
 
 
2425
        EXIT3(return);
 
2426
}
 
2427
 
 
2428
/* called via function pointer */
 
2429
wstdcall void NdisMTransferDataComplete(struct ndis_mp_block *nmb,
 
2430
                                        struct ndis_packet *packet,
 
2431
                                        NDIS_STATUS status, UINT bytes_txed)
 
2432
{
 
2433
        struct ndis_device *wnd = nmb->wnd;
 
2434
        struct sk_buff *skb;
 
2435
        unsigned int skb_size;
 
2436
        struct ndis_packet_oob_data *oob_data;
 
2437
        ndis_buffer *buffer;
 
2438
        struct ndis_tcp_ip_checksum_packet_info csum;
 
2439
 
 
2440
        ENTER3("wnd = %p, packet = %p, bytes_txed = %d",
 
2441
               wnd, packet, bytes_txed);
 
2442
        if (!packet) {
 
2443
                WARNING("illegal packet");
 
2444
                EXIT3(return);
 
2445
        }
 
2446
        wnd->net_dev->last_rx = jiffies;
 
2447
        oob_data = NDIS_PACKET_OOB_DATA(packet);
 
2448
        skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size +
 
2449
                bytes_txed;
 
2450
        skb = dev_alloc_skb(skb_size);
 
2451
        if (!skb) {
 
2452
                kfree(oob_data->look_ahead);
 
2453
                NdisFreePacket(packet);
 
2454
                ERROR("couldn't allocate skb; packet dropped");
 
2455
                atomic_inc_var(wnd->net_stats.rx_dropped);
 
2456
                EXIT3(return);
 
2457
        }
 
2458
        memcpy_skb(skb, oob_data->header, sizeof(oob_data->header));
 
2459
        memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size);
 
2460
        buffer = packet->private.buffer_head;
 
2461
        while (buffer) {
 
2462
                memcpy_skb(skb, MmGetSystemAddressForMdl(buffer),
 
2463
                           MmGetMdlByteCount(buffer));
 
2464
                buffer = buffer->next;
 
2465
        }
 
2466
        kfree(oob_data->look_ahead);
 
2467
        NdisFreePacket(packet);
 
2468
        skb->dev = wnd->net_dev;
 
2469
        skb->protocol = eth_type_trans(skb, wnd->net_dev);
 
2470
        pre_atomic_add(wnd->net_stats.rx_bytes, skb_size);
 
2471
        atomic_inc_var(wnd->net_stats.rx_packets);
 
2472
 
 
2473
        csum.value = (typeof(csum.value))(ULONG_PTR)
 
2474
                oob_data->ext.info[TcpIpChecksumPacketInfo];
 
2475
        TRACE3("0x%05x", csum.value);
 
2476
        if (wnd->rx_csum.value &&
 
2477
            (csum.rx.tcp_succeeded || csum.rx.udp_succeeded))
 
2478
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
2479
        else
 
2480
                skb->ip_summed = CHECKSUM_NONE;
 
2481
 
 
2482
        if (in_interrupt())
 
2483
                netif_rx(skb);
 
2484
        else
 
2485
                netif_rx_ni(skb);
 
2486
}
 
2487
 
 
2488
/* called via function pointer */
 
2489
wstdcall void EthRxComplete(struct ndis_mp_block *nmb)
 
2490
{
 
2491
        TRACE3("");
 
2492
}
 
2493
 
 
2494
/* called via function pointer */
 
2495
wstdcall void NdisMQueryInformationComplete(struct ndis_mp_block *nmb,
 
2496
                                            NDIS_STATUS status)
 
2497
{
 
2498
        struct ndis_device *wnd = nmb->wnd;
 
2499
        typeof(wnd->ndis_req_task) task;
 
2500
 
 
2501
        ENTER2("nmb: %p, wnd: %p, %08X", nmb, wnd, status);
 
2502
        wnd->ndis_req_status = status;
 
2503
        wnd->ndis_req_done = 1;
 
2504
        if ((task = xchg(&wnd->ndis_req_task, NULL)))
 
2505
                wake_up_process(task);
 
2506
        else
 
2507
                WARNING("invalid task");
 
2508
        EXIT2(return);
 
2509
}
 
2510
 
 
2511
/* called via function pointer */
 
2512
wstdcall void NdisMSetInformationComplete(struct ndis_mp_block *nmb,
 
2513
                                          NDIS_STATUS status)
 
2514
{
 
2515
        struct ndis_device *wnd = nmb->wnd;
 
2516
        typeof(wnd->ndis_req_task) task;
 
2517
 
 
2518
        ENTER2("status = %08X", status);
 
2519
        wnd->ndis_req_status = status;
 
2520
        wnd->ndis_req_done = 1;
 
2521
        if ((task = xchg(&wnd->ndis_req_task, NULL)))
 
2522
                wake_up_process(task);
 
2523
        else
 
2524
                WARNING("invalid task");
 
2525
        EXIT2(return);
 
2526
}
 
2527
 
 
2528
/* called via function pointer */
 
2529
wstdcall void NdisMResetComplete(struct ndis_mp_block *nmb,
 
2530
                                 NDIS_STATUS status, BOOLEAN address_reset)
 
2531
{
 
2532
        struct ndis_device *wnd = nmb->wnd;
 
2533
        typeof(wnd->ndis_req_task) task;
 
2534
 
 
2535
        ENTER2("status: %08X, %u", status, address_reset);
 
2536
        wnd->ndis_req_status = status;
 
2537
        wnd->ndis_req_done = address_reset + 1;
 
2538
        if ((task = xchg(&wnd->ndis_req_task, NULL)))
 
2539
                wake_up_process(task);
 
2540
        else
 
2541
                WARNING("invalid task");
 
2542
        EXIT2(return);
 
2543
}
 
2544
 
 
2545
wstdcall void WIN_FUNC(NdisMSleep,1)
 
2546
        (ULONG us)
 
2547
{
 
2548
        unsigned long delay;
 
2549
 
 
2550
        ENTER4("%p: us: %u", current, us);
 
2551
        delay = USEC_TO_HZ(us);
 
2552
        sleep_hz(delay);
 
2553
        TRACE4("%p: done", current);
 
2554
}
 
2555
 
 
2556
wstdcall void WIN_FUNC(NdisGetCurrentSystemTime,1)
 
2557
        (LARGE_INTEGER *time)
 
2558
{
 
2559
        *time = ticks_1601();
 
2560
        TRACE5("%Lu, %lu", *time, jiffies);
 
2561
}
 
2562
 
 
2563
wstdcall LONG WIN_FUNC(NdisInterlockedDecrement,1)
 
2564
        (LONG *val)
 
2565
{
 
2566
        return InterlockedDecrement(val);
 
2567
}
 
2568
 
 
2569
wstdcall LONG WIN_FUNC(NdisInterlockedIncrement,1)
 
2570
        (LONG *val)
 
2571
{
 
2572
        return InterlockedIncrement(val);
 
2573
}
 
2574
 
 
2575
wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertHeadList,3)
 
2576
        (struct nt_list *head, struct nt_list *entry,
 
2577
         struct ndis_spinlock *lock)
 
2578
{
 
2579
        return ExInterlockedInsertHeadList(head, entry, &lock->klock);
 
2580
}
 
2581
 
 
2582
wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertTailList,3)
 
2583
        (struct nt_list *head, struct nt_list *entry,
 
2584
         struct ndis_spinlock *lock)
 
2585
{
 
2586
        return ExInterlockedInsertTailList(head, entry, &lock->klock);
 
2587
}
 
2588
 
 
2589
wstdcall struct nt_list *WIN_FUNC(NdisInterlockedRemoveHeadList,2)
 
2590
        (struct nt_list *head, struct ndis_spinlock *lock)
 
2591
{
 
2592
        return ExInterlockedRemoveHeadList(head, &lock->klock);
 
2593
}
 
2594
 
 
2595
wstdcall NDIS_STATUS WIN_FUNC(NdisMInitializeScatterGatherDma,3)
 
2596
        (struct ndis_mp_block *nmb, BOOLEAN dma_size, ULONG max_phy_map)
 
2597
{
 
2598
        struct ndis_device *wnd = nmb->wnd;
 
2599
        ENTER2("dma_size=%d, maxtransfer=%u", dma_size, max_phy_map);
 
2600
#ifdef CONFIG_X86_64
 
2601
        if (dma_size != NDIS_DMA_64BITS) {
 
2602
                TRACE1("DMA size is not 64-bits");
 
2603
                if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)) ||
 
2604
                    pci_set_consistent_dma_mask(wnd->wd->pci.pdev,
 
2605
                                                DMA_BIT_MASK(32)))
 
2606
                        WARNING("setting dma mask failed");
 
2607
        }
 
2608
#endif
 
2609
        if ((wnd->attributes & NDIS_ATTRIBUTE_BUS_MASTER) &&
 
2610
            wrap_is_pci_bus(wnd->wd->dev_bus)) {
 
2611
                wnd->sg_dma_size = max_phy_map;
 
2612
                return NDIS_STATUS_SUCCESS;
 
2613
        } else
 
2614
                EXIT1(return NDIS_STATUS_NOT_SUPPORTED);
 
2615
}
 
2616
 
 
2617
wstdcall ULONG WIN_FUNC(NdisMGetDmaAlignment,1)
 
2618
        (struct ndis_mp_block *nmb)
 
2619
{
 
2620
        ENTER3("");
 
2621
        return dma_get_cache_alignment();
 
2622
}
 
2623
 
 
2624
wstdcall CHAR WIN_FUNC(NdisSystemProcessorCount,0)
 
2625
        (void)
 
2626
{
 
2627
        return (CHAR)NR_CPUS;
 
2628
}
 
2629
 
 
2630
wstdcall void WIN_FUNC(NdisGetCurrentProcessorCounts,3)
 
2631
        (ULONG *idle, ULONG *kernel_user, ULONG *index)
 
2632
{
 
2633
        int cpu = smp_processor_id();
 
2634
        *idle = kstat_cpu(cpu).cpustat.idle;
 
2635
        *kernel_user = kstat_cpu(cpu).cpustat.system +
 
2636
                kstat_cpu(cpu).cpustat.user;
 
2637
        *index = cpu;
 
2638
}
 
2639
 
 
2640
wstdcall void WIN_FUNC(NdisInitializeEvent,1)
 
2641
        (struct ndis_event *ndis_event)
 
2642
{
 
2643
        EVENTENTER("%p", ndis_event);
 
2644
        KeInitializeEvent(&ndis_event->nt_event, NotificationEvent, 0);
 
2645
}
 
2646
 
 
2647
wstdcall BOOLEAN WIN_FUNC(NdisWaitEvent,2)
 
2648
        (struct ndis_event *ndis_event, UINT ms)
 
2649
{
 
2650
        LARGE_INTEGER ticks;
 
2651
        NTSTATUS res;
 
2652
 
 
2653
        EVENTENTER("%p %u", ndis_event, ms);
 
2654
        ticks = -((LARGE_INTEGER)ms * TICKSPERMSEC);
 
2655
        res = KeWaitForSingleObject(&ndis_event->nt_event, 0, 0, TRUE,
 
2656
                                    ms == 0 ? NULL : &ticks);
 
2657
        if (res == STATUS_SUCCESS)
 
2658
                EXIT3(return TRUE);
 
2659
        else
 
2660
                EXIT3(return FALSE);
 
2661
}
 
2662
 
 
2663
wstdcall void WIN_FUNC(NdisSetEvent,1)
 
2664
        (struct ndis_event *ndis_event)
 
2665
{
 
2666
        EVENTENTER("%p", ndis_event);
 
2667
        KeSetEvent(&ndis_event->nt_event, 0, 0);
 
2668
}
 
2669
 
 
2670
wstdcall void WIN_FUNC(NdisResetEvent,1)
 
2671
        (struct ndis_event *ndis_event)
 
2672
{
 
2673
        EVENTENTER("%p", ndis_event);
 
2674
        KeResetEvent(&ndis_event->nt_event);
 
2675
}
 
2676
 
 
2677
static void ndis_worker(worker_param_t dummy)
 
2678
{
 
2679
        struct nt_list *ent;
 
2680
        struct ndis_work_item *ndis_work_item;
 
2681
 
 
2682
        WORKENTER("");
 
2683
        while (1) {
 
2684
                spin_lock_bh(&ndis_work_list_lock);
 
2685
                ent = RemoveHeadList(&ndis_work_list);
 
2686
                spin_unlock_bh(&ndis_work_list_lock);
 
2687
                if (!ent)
 
2688
                        break;
 
2689
                ndis_work_item = container_of(ent, struct ndis_work_item, list);
 
2690
                WORKTRACE("%p: %p, %p", ndis_work_item,
 
2691
                          ndis_work_item->func, ndis_work_item->ctx);
 
2692
                LIN2WIN2(ndis_work_item->func, ndis_work_item,
 
2693
                         ndis_work_item->ctx);
 
2694
                WORKTRACE("%p done", ndis_work_item);
 
2695
        }
 
2696
        WORKEXIT(return);
 
2697
}
 
2698
 
 
2699
wstdcall NDIS_STATUS WIN_FUNC(NdisScheduleWorkItem,1)
 
2700
        (struct ndis_work_item *ndis_work_item)
 
2701
{
 
2702
        ENTER3("%p", ndis_work_item);
 
2703
        spin_lock_bh(&ndis_work_list_lock);
 
2704
        InsertTailList(&ndis_work_list, &ndis_work_item->list);
 
2705
        spin_unlock_bh(&ndis_work_list_lock);
 
2706
        WORKTRACE("scheduling %p", ndis_work_item);
 
2707
        schedule_ndis_work(&ndis_work);
 
2708
        EXIT3(return NDIS_STATUS_SUCCESS);
 
2709
}
 
2710
 
 
2711
wstdcall void WIN_FUNC(NdisMGetDeviceProperty,6)
 
2712
        (struct ndis_mp_block *nmb, void **phy_dev, void **func_dev,
 
2713
         void **next_dev, void **alloc_res, void**trans_res)
 
2714
{
 
2715
        ENTER2("nmb: %p, phy_dev = %p, func_dev = %p, next_dev = %p, "
 
2716
               "alloc_res = %p, trans_res = %p", nmb, phy_dev, func_dev,
 
2717
               next_dev, alloc_res, trans_res);
 
2718
        if (phy_dev)
 
2719
                *phy_dev = nmb->pdo;
 
2720
        if (func_dev)
 
2721
                *func_dev = nmb->fdo;
 
2722
        if (next_dev)
 
2723
                *next_dev = nmb->next_device;
 
2724
}
 
2725
 
 
2726
wstdcall void WIN_FUNC(NdisMRegisterUnloadHandler,2)
 
2727
        (struct driver_object *drv_obj, void *unload)
 
2728
{
 
2729
        if (drv_obj)
 
2730
                drv_obj->unload = unload;
 
2731
        return;
 
2732
}
 
2733
 
 
2734
wstdcall UINT WIN_FUNC(NdisGetVersion,0)
 
2735
        (void)
 
2736
{
 
2737
        return 0x00050001;
 
2738
}
 
2739
 
 
2740
wstdcall NDIS_STATUS WIN_FUNC(NdisMQueryAdapterInstanceName,2)
 
2741
        (struct unicode_string *name, struct ndis_mp_block *nmb)
 
2742
{
 
2743
        struct ndis_device *wnd = nmb->wnd;
 
2744
        struct ansi_string ansi;
 
2745
 
 
2746
        if (wrap_is_pci_bus(wnd->wd->dev_bus))
 
2747
                RtlInitAnsiString(&ansi, "PCI Ethernet Adapter");
 
2748
        else
 
2749
                RtlInitAnsiString(&ansi, "USB Ethernet Adapter");
 
2750
 
 
2751
        if (RtlAnsiStringToUnicodeString(name, &ansi, TRUE))
 
2752
                EXIT2(return NDIS_STATUS_RESOURCES);
 
2753
        else
 
2754
                EXIT2(return NDIS_STATUS_SUCCESS);
 
2755
}
 
2756
 
 
2757
wstdcall NDIS_STATUS WIN_FUNC(NdisWriteEventLogEntry,7)
 
2758
        (void *handle, NDIS_STATUS code, ULONG value, USHORT n,
 
2759
         void *strings, ULONG datasize, void *data)
 
2760
{
 
2761
        TRACE1("0x%x, 0x%x, %u, %u", code, value, n, datasize);
 
2762
        return NDIS_STATUS_SUCCESS;
 
2763
}
 
2764
 
 
2765
wstdcall void *WIN_FUNC(NdisGetRoutineAddress,1)
 
2766
        (struct unicode_string *unicode_string)
 
2767
{
 
2768
        struct ansi_string ansi_string;
 
2769
        void *address;
 
2770
 
 
2771
        if (RtlUnicodeStringToAnsiString(&ansi_string, unicode_string, TRUE) !=
 
2772
            STATUS_SUCCESS)
 
2773
                EXIT1(return NULL);
 
2774
        INFO("%s", ansi_string.buf);
 
2775
        address = ndis_get_routine_address(ansi_string.buf);
 
2776
        RtlFreeAnsiString(&ansi_string);
 
2777
        return address;
 
2778
}
 
2779
 
 
2780
wstdcall ULONG WIN_FUNC(NdisReadPcmciaAttributeMemory,4)
 
2781
        (struct ndis_mp_block *nmb, ULONG offset, void *buffer,
 
2782
         ULONG length)
 
2783
{
 
2784
        TODO();
 
2785
        return 0;
 
2786
}
 
2787
 
 
2788
wstdcall ULONG WIN_FUNC(NdisWritePcmciaAttributeMemory,4)
 
2789
        (struct ndis_mp_block *nmb, ULONG offset, void *buffer,
 
2790
         ULONG length)
 
2791
{
 
2792
        TODO();
 
2793
        return 0;
 
2794
}
 
2795
 
 
2796
wstdcall void WIN_FUNC(NdisMCoIndicateReceivePacket,3)
 
2797
        (struct ndis_mp_block *nmb, struct ndis_packet **packets,
 
2798
         UINT nr_packets)
 
2799
{
 
2800
        ENTER3("nmb = %p", nmb);
 
2801
        NdisMIndicateReceivePacket(nmb, packets, nr_packets);
 
2802
        EXIT3(return);
 
2803
}
 
2804
 
 
2805
wstdcall void WIN_FUNC(NdisMCoSendComplete,3)
 
2806
        (NDIS_STATUS status, struct ndis_mp_block *nmb,
 
2807
         struct ndis_packet *packet)
 
2808
{
 
2809
        ENTER3("%08x", status);
 
2810
        NdisMSendComplete(nmb, packet, status);
 
2811
        EXIT3(return);
 
2812
}
 
2813
 
 
2814
wstdcall void WIN_FUNC(NdisMCoRequestComplete,3)
 
2815
        (NDIS_STATUS status, struct ndis_mp_block *nmb,
 
2816
         struct ndis_request *ndis_request)
 
2817
{
 
2818
        struct ndis_device *wnd = nmb->wnd;
 
2819
        typeof(wnd->ndis_req_task) task;
 
2820
 
 
2821
        ENTER3("%08X", status);
 
2822
        wnd->ndis_req_status = status;
 
2823
        wnd->ndis_req_done = 1;
 
2824
        if ((task = xchg(&wnd->ndis_req_task, NULL)))
 
2825
                wake_up_process(task);
 
2826
        else
 
2827
                WARNING("invalid task");
 
2828
        EXIT3(return);
 
2829
}
 
2830
 
 
2831
wstdcall NDIS_STATUS WIN_FUNC(NdisIMNotifiyPnPEvent,2)
 
2832
        (struct ndis_mp_block *nmb, struct net_pnp_event *event)
 
2833
{
 
2834
        ENTER2("%p, %d", nmb, event->code);
 
2835
        /* NdisWrapper never calls protocol's pnp event notifier, so
 
2836
         * nothing to do here */
 
2837
        EXIT2(return NDIS_STATUS_SUCCESS);
 
2838
}
 
2839
 
 
2840
wstdcall void WIN_FUNC(NdisCompletePnPEvent,2)
 
2841
        (NDIS_STATUS status, void *handle, struct net_pnp_event *event)
 
2842
{
 
2843
        ENTER2("%d, %p, %d", status, handle, event->code);
 
2844
        /* NdisWrapper never calls protocol's pnp event notifier, so
 
2845
         * nothing to do here */
 
2846
        EXIT2(return);
 
2847
}
 
2848
 
 
2849
wstdcall NDIS_STATUS WIN_FUNC(NdisMSetMiniportSecondary,2)
 
2850
        (struct ndis_mp_block *nmb2, struct ndis_mp_block *nmb1)
 
2851
{
 
2852
        ENTER3("%p, %p", nmb1, nmb2);
 
2853
        TODO();
 
2854
        EXIT3(return NDIS_STATUS_SUCCESS);
 
2855
}
 
2856
 
 
2857
wstdcall NDIS_STATUS WIN_FUNC(NdisMPromoteMiniport,1)
 
2858
        (struct ndis_mp_block *nmb)
 
2859
{
 
2860
        ENTER3("%p", nmb);
 
2861
        TODO();
 
2862
        EXIT3(return NDIS_STATUS_SUCCESS);
 
2863
}
 
2864
 
 
2865
wstdcall void WIN_FUNC(NdisMCoActivateVcComplete,3)
 
2866
        (NDIS_STATUS status, void *handle, void *params)
 
2867
{
 
2868
        TODO();
 
2869
}
 
2870
 
 
2871
wstdcall void WIN_FUNC(NdisMCoDeactivateVcComplete,2)
 
2872
        (NDIS_STATUS status, void *handle)
 
2873
{
 
2874
        TODO();
 
2875
}
 
2876
 
 
2877
wstdcall void WIN_FUNC(NdisMRemoveMiniport,1)
 
2878
        (void *handle)
 
2879
{
 
2880
        TODO();
 
2881
}
 
2882
 
 
2883
static void *ndis_get_routine_address(char *name)
 
2884
{
 
2885
        int i;
 
2886
        ENTER2("%p", name);
 
2887
        for (i = 0; i < sizeof(ndis_exports) / sizeof(ndis_exports[0]); i++) {
 
2888
                if (strcmp(name, ndis_exports[i].name) == 0) {
 
2889
                        TRACE2("%p", ndis_exports[i].func);
 
2890
                        return ndis_exports[i].func;
 
2891
                }
 
2892
        }
 
2893
        EXIT2(return NULL);
 
2894
}
 
2895
 
 
2896
/* ndis_init_device is called for each device */
 
2897
int ndis_init_device(struct ndis_device *wnd)
 
2898
{
 
2899
        struct ndis_mp_block *nmb = wnd->nmb;
 
2900
 
 
2901
        KeInitializeSpinLock(&nmb->lock);
 
2902
        wnd->mp_interrupt = NULL;
 
2903
        wnd->wrap_timer_slist.next = NULL;
 
2904
        if (wnd->wd->driver->ndis_driver)
 
2905
                wnd->wd->driver->ndis_driver->mp.shutdown = NULL;
 
2906
 
 
2907
        nmb->filterdbs.eth_db = nmb;
 
2908
        nmb->filterdbs.tr_db = nmb;
 
2909
        nmb->filterdbs.fddi_db = nmb;
 
2910
        nmb->filterdbs.arc_db = nmb;
 
2911
 
 
2912
        nmb->rx_packet = WIN_FUNC_PTR(NdisMIndicateReceivePacket,3);
 
2913
        nmb->send_complete = WIN_FUNC_PTR(NdisMSendComplete,3);
 
2914
        nmb->send_resource_avail = WIN_FUNC_PTR(NdisMSendResourcesAvailable,1);
 
2915
        nmb->status = WIN_FUNC_PTR(NdisMIndicateStatus,4);
 
2916
        nmb->status_complete = WIN_FUNC_PTR(NdisMIndicateStatusComplete,1);
 
2917
        nmb->queryinfo_complete = WIN_FUNC_PTR(NdisMQueryInformationComplete,2);
 
2918
        nmb->setinfo_complete = WIN_FUNC_PTR(NdisMSetInformationComplete,2);
 
2919
        nmb->reset_complete = WIN_FUNC_PTR(NdisMResetComplete,3);
 
2920
        nmb->eth_rx_indicate = WIN_FUNC_PTR(EthRxIndicateHandler,8);
 
2921
        nmb->eth_rx_complete = WIN_FUNC_PTR(EthRxComplete,1);
 
2922
        nmb->td_complete = WIN_FUNC_PTR(NdisMTransferDataComplete,4);
 
2923
        return 0;
 
2924
}
 
2925
 
 
2926
/* ndis_exit_device is called for each device */
 
2927
void ndis_exit_device(struct ndis_device *wnd)
 
2928
{
 
2929
        struct wrap_device_setting *setting;
 
2930
        ENTER2("%p", wnd);
 
2931
        if (down_interruptible(&loader_mutex))
 
2932
                WARNING("couldn't obtain loader_mutex");
 
2933
        nt_list_for_each_entry(setting, &wnd->wd->settings, list) {
 
2934
                struct ndis_configuration_parameter *param;
 
2935
                param = setting->encoded;
 
2936
                if (param) {
 
2937
                        if (param->type == NdisParameterString)
 
2938
                                RtlFreeUnicodeString(&param->data.string);
 
2939
                        ExFreePool(param);
 
2940
                        setting->encoded = NULL;
 
2941
                }
 
2942
        }
 
2943
        up(&loader_mutex);
 
2944
}
 
2945
 
 
2946
/* ndis_init is called once when module is loaded */
 
2947
int ndis_init(void)
 
2948
{
 
2949
        InitializeListHead(&ndis_work_list);
 
2950
        spin_lock_init(&ndis_work_list_lock);
 
2951
        initialize_work(&ndis_work, ndis_worker, NULL);
 
2952
 
 
2953
        ndis_wq = create_singlethread_workqueue("ndis_wq");
 
2954
        if (!ndis_wq) {
 
2955
                WARNING("couldn't create worker thread");
 
2956
                EXIT1(return -ENOMEM);
 
2957
        }
 
2958
 
 
2959
        ndis_worker_thread = wrap_worker_init(ndis_wq);
 
2960
        TRACE1("%p", ndis_worker_thread);
 
2961
        return 0;
 
2962
}
 
2963
 
 
2964
/* ndis_exit is called once when module is removed */
 
2965
void ndis_exit(void)
 
2966
{
 
2967
        ENTER1("");
 
2968
        if (ndis_wq)
 
2969
                destroy_workqueue(ndis_wq);
 
2970
        TRACE1("%p", ndis_worker_thread);
 
2971
        if (ndis_worker_thread)
 
2972
                ObDereferenceObject(ndis_worker_thread);
 
2973
        EXIT1(return);
 
2974
}