win-pvdrivers

view xennet/xennet.c @ 821:9c0c4210b778

Fix xennet build under Windows 2000
Fix xenvbd install under Windows 2000
author James Harper <james.harper@bendigoit.com.au>
date Sat Oct 16 20:03:30 2010 +1100 (2010-10-16)
parents 678c7d92321c
children 42f72a7b5f1f
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include <stdlib.h>
22 #include <io/xenbus.h>
23 #include "xennet.h"
25 /* Not really necessary but keeps PREfast happy */
26 DRIVER_INITIALIZE DriverEntry;
27 static IO_WORKITEM_ROUTINE XenNet_Resume;
28 #if (NTDDI_VERSION >= NTDDI_WINXP)
29 static KDEFERRED_ROUTINE XenNet_SuspendResume;
30 #endif
32 #pragma NDIS_INIT_FUNCTION(DriverEntry)
34 /* ----- BEGIN Other people's code --------- */
35 /* from linux/include/linux/ctype.h, used under GPLv2 */
36 #define _U 0x01 /* upper */
37 #define _L 0x02 /* lower */
38 #define _D 0x04 /* digit */
39 #define _C 0x08 /* cntrl */
40 #define _P 0x10 /* punct */
41 #define _S 0x20 /* white space (space/lf/tab) */
42 #define _X 0x40 /* hex digit */
43 #define _SP 0x80 /* hard space (0x20) */
45 /* from linux/include/lib/ctype.c, used under GPLv2 */
46 unsigned char _ctype[] = {
47 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
48 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
49 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
50 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
51 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
52 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
53 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
54 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
55 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
56 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
57 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
58 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
59 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
60 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
61 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
62 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
63 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
64 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
65 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
66 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
67 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
68 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
69 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
70 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
72 /* from linux/include/linux/ctype.h, used under GPLv2 */
73 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
75 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
76 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
77 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
78 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
79 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
80 #define islower(c) ((__ismask(c)&(_L)) != 0)
81 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
82 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
83 #define isspace(c) ((__ismask(c)&(_S)) != 0)
84 #define isupper(c) ((__ismask(c)&(_U)) != 0)
85 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
87 #define TOLOWER(x) ((x) | 0x20)
89 /* from linux/lib/vsprintf.c, used under GPLv2 */
90 /* Copyright (C) 1991, 1992 Linus Torvalds
91 * Wirzenius wrote this portably, Torvalds fucked it up :-)
92 */
93 /**
94 * simple_strtoul - convert a string to an unsigned long
95 * @cp: The start of the string
96 * @endp: A pointer to the end of the parsed string will be placed here
97 * @base: The number base to use
98 */
99 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
100 {
101 unsigned long result = 0,value;
103 if (!base) {
104 base = 10;
105 if (*cp == '0') {
106 base = 8;
107 cp++;
108 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
109 cp++;
110 base = 16;
111 }
112 }
113 } else if (base == 16) {
114 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
115 cp += 2;
116 }
117 while (isxdigit(*cp) &&
118 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
119 result = result*base + value;
120 cp++;
121 }
122 if (endp)
123 *endp = (char *)cp;
124 return result;
125 }
126 /* end vsprintf.c code */
127 /* ----- END Other people's code --------- */
129 static NDIS_STATUS
130 XenNet_ConnectBackend(struct xennet_info *xi)
131 {
132 PUCHAR ptr;
133 UCHAR type;
134 PCHAR setting, value, value2;
135 UINT i;
136 ULONG backend_sg = 0;
137 ULONG backend_gso = 0;
139 FUNCTION_ENTER();
141 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
143 ptr = xi->config_page;
144 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
145 {
146 switch(type)
147 {
148 case XEN_INIT_TYPE_RING: /* frontend ring */
149 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
150 if (strcmp(setting, "tx-ring-ref") == 0)
151 {
152 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
153 } else if (strcmp(setting, "rx-ring-ref") == 0)
154 {
155 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
156 }
157 break;
158 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
159 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
160 if (strcmp(setting, "event-channel") == 0)
161 {
162 xi->event_channel = PtrToUlong(value);
163 }
164 break;
165 case XEN_INIT_TYPE_READ_STRING_FRONT:
166 break;
167 case XEN_INIT_TYPE_READ_STRING_BACK:
168 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
169 if (strcmp(setting, "mac") == 0)
170 {
171 char *s, *e;
172 s = value;
173 for (i = 0; i < ETH_ALEN; i++) {
174 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
175 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
176 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
177 }
178 s = e + 1;
179 }
180 if ((xi->curr_mac_addr[0] & 0x03) != 0x02)
181 {
182 /* only copy if curr_mac_addr is not a LUA */
183 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
184 }
185 }
186 else if (strcmp(setting, "feature-sg") == 0)
187 {
188 if (atoi(value))
189 {
190 backend_sg = 1;
191 }
192 }
193 else if (strcmp(setting, "feature-gso-tcpv4") == 0)
194 {
195 if (atoi(value))
196 {
197 backend_gso = 1;
198 }
199 }
200 break;
201 case XEN_INIT_TYPE_VECTORS:
202 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
203 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
204 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
205 {
206 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
207 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
208 FUNCTION_EXIT();
209 return NDIS_STATUS_ADAPTER_NOT_FOUND;
210 }
211 else
212 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
213 break;
214 case XEN_INIT_TYPE_STATE_PTR:
215 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
216 xi->device_state = (PXENPCI_DEVICE_STATE)value;
217 break;
218 default:
219 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
220 break;
221 }
222 }
223 if (xi->config_sg && !backend_sg)
224 {
225 KdPrint((__DRIVER_NAME " SG not supported by backend - disabling\n"));
226 xi->config_sg = 0;
227 }
228 if (xi->config_gso && !backend_gso)
229 {
230 KdPrint((__DRIVER_NAME " GSO not supported by backend - disabling\n"));
231 xi->config_gso = 0;
232 }
233 FUNCTION_EXIT();
235 return NDIS_STATUS_SUCCESS;
236 }
238 static DDKAPI VOID
239 XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
240 {
241 struct xennet_info *xi = context;
243 UNREFERENCED_PARAMETER(device_object);
245 FUNCTION_ENTER();
247 ASSERT(xi->resume_work_item);
248 IoFreeWorkItem(xi->resume_work_item);
249 xi->resume_work_item = NULL;
251 XenNet_TxResumeStart(xi);
252 XenNet_RxResumeStart(xi);
253 XenNet_ConnectBackend(xi);
254 XenNet_RxResumeEnd(xi);
255 XenNet_TxResumeEnd(xi);
256 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
257 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
258 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
259 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
261 FUNCTION_EXIT();
263 }
265 static VOID
266 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
267 {
268 struct xennet_info *xi = context;
269 KIRQL old_irql;
271 UNREFERENCED_PARAMETER(dpc);
272 UNREFERENCED_PARAMETER(arg1);
273 UNREFERENCED_PARAMETER(arg2);
275 FUNCTION_ENTER();
277 switch (xi->device_state->suspend_resume_state_pdo)
278 {
279 case SR_STATE_SUSPENDING:
280 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
281 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
282 if (xi->rx_id_free == NET_TX_RING_SIZE)
283 {
284 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
285 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
286 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
287 }
288 KeReleaseSpinLock(&xi->rx_lock, old_irql);
289 break;
290 case SR_STATE_RESUMING:
291 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
292 ASSERT(!xi->resume_work_item);
293 xi->resume_work_item = IoAllocateWorkItem(xi->fdo);
294 IoQueueWorkItem(xi->resume_work_item, XenNet_Resume, DelayedWorkQueue, xi);
295 break;
296 default:
297 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
298 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
299 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
300 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
301 break;
302 }
303 KeMemoryBarrier();
305 FUNCTION_EXIT();
306 }
308 static DDKAPI BOOLEAN
309 XenNet_HandleEvent(PVOID context)
310 {
311 struct xennet_info *xi = context;
312 ULONG suspend_resume_state_pdo;
314 //FUNCTION_ENTER();
315 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
316 KeMemoryBarrier();
317 // KdPrint((__DRIVER_NAME " connected = %d, inactive = %d, suspend_resume_state_pdo = %d\n",
318 // xi->connected, xi->inactive, suspend_resume_state_pdo));
319 if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
320 {
321 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
322 }
323 if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
324 {
325 KeInsertQueueDpc(&xi->tx_dpc, NULL, NULL);
326 KeInsertQueueDpc(&xi->rx_dpc, NULL, NULL);
327 }
328 //FUNCTION_EXIT();
329 return TRUE;
330 }
332 VOID
333 XenNet_SetPower(PDEVICE_OBJECT device_object, PVOID context)
334 {
335 NTSTATUS status = STATUS_SUCCESS;
336 KIRQL old_irql;
337 struct xennet_info *xi = context;
339 FUNCTION_ENTER();
340 UNREFERENCED_PARAMETER(device_object);
342 switch (xi->new_power_state)
343 {
344 case NdisDeviceStateD0:
345 KdPrint((" NdisDeviceStateD0\n"));
346 status = XenNet_D0Entry(xi);
347 break;
348 case NdisDeviceStateD1:
349 KdPrint((" NdisDeviceStateD1\n"));
350 if (xi->power_state == NdisDeviceStateD0)
351 status = XenNet_D0Exit(xi);
352 break;
353 case NdisDeviceStateD2:
354 KdPrint((" NdisDeviceStateD2\n"));
355 if (xi->power_state == NdisDeviceStateD0)
356 status = XenNet_D0Exit(xi);
357 break;
358 case NdisDeviceStateD3:
359 KdPrint((" NdisDeviceStateD3\n"));
360 if (xi->power_state == NdisDeviceStateD0)
361 status = XenNet_D0Exit(xi);
362 break;
363 default:
364 KdPrint((" NdisDeviceState??\n"));
365 status = NDIS_STATUS_NOT_SUPPORTED;
366 break;
367 }
368 xi->power_state = xi->new_power_state;
370 old_irql = KeRaiseIrqlToDpcLevel();
371 NdisMSetInformationComplete(xi->adapter_handle, status);
372 KeLowerIrql(old_irql);
374 FUNCTION_EXIT();
375 }
377 NDIS_STATUS
378 XenNet_D0Entry(struct xennet_info *xi)
379 {
380 NDIS_STATUS status;
381 PUCHAR ptr;
382 CHAR buf[128];
384 FUNCTION_ENTER();
386 xi->shutting_down = FALSE;
388 ptr = xi->config_page;
389 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
390 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
391 #pragma warning(suppress:4054)
392 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
393 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
394 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
395 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
396 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
397 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
398 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
399 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
400 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
401 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
402 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
403 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
404 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
405 __ADD_XEN_INIT_UCHAR(&ptr, 0); /* no pre-connect required */
406 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
407 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
408 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
409 __ADD_XEN_INIT_UCHAR(&ptr, 20);
410 __ADD_XEN_INIT_UCHAR(&ptr, 0);
411 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_SHUTDOWN, NULL, NULL, NULL);
412 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
413 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
414 __ADD_XEN_INIT_UCHAR(&ptr, 50);
415 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
416 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
417 __ADD_XEN_INIT_UCHAR(&ptr, 50);
418 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitialising);
419 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitWait);
420 __ADD_XEN_INIT_UCHAR(&ptr, 50);
421 __ADD_XEN_INIT_UCHAR(&ptr, 0);
422 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
424 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
425 if (!NT_SUCCESS(status))
426 {
427 KdPrint(("Failed to complete device configuration (%08x)\n", status));
428 return status;
429 }
431 status = XenNet_ConnectBackend(xi);
433 if (!NT_SUCCESS(status))
434 {
435 KdPrint(("Failed to complete device configuration (%08x)\n", status));
436 return status;
437 }
439 if (!xi->config_sg)
440 {
441 /* without SG, GSO can be a maximum of PAGE_SIZE */
442 xi->config_gso = min(xi->config_gso, PAGE_SIZE);
443 }
445 XenNet_TxInit(xi);
446 XenNet_RxInit(xi);
448 xi->connected = TRUE;
450 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
452 FUNCTION_EXIT();
454 return status;
455 }
457 // Called at <= DISPATCH_LEVEL
458 static NDIS_STATUS
459 XenNet_Init(
460 OUT PNDIS_STATUS OpenErrorStatus,
461 OUT PUINT SelectedMediumIndex,
462 IN PNDIS_MEDIUM MediumArray,
463 IN UINT MediumArraySize,
464 IN NDIS_HANDLE MiniportAdapterHandle,
465 IN NDIS_HANDLE WrapperConfigurationContext
466 )
467 {
468 NDIS_STATUS status;
469 BOOLEAN medium_found = FALSE;
470 struct xennet_info *xi = NULL;
471 UINT nrl_length;
472 PNDIS_RESOURCE_LIST nrl;
473 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
474 KIRQL irq_level = 0;
475 ULONG irq_vector = 0;
476 ULONG irq_mode = 0;
477 NDIS_HANDLE config_handle;
478 NDIS_STRING config_param_name;
479 PNDIS_CONFIGURATION_PARAMETER config_param;
480 ULONG i;
481 PUCHAR ptr;
482 UCHAR type;
483 PCHAR setting, value;
484 ULONG length;
485 //CHAR buf[128];
486 PVOID network_address;
487 UINT network_address_length;
488 BOOLEAN qemu_hide_filter = FALSE;
489 ULONG qemu_hide_flags_value = 0;
491 UNREFERENCED_PARAMETER(OpenErrorStatus);
493 FUNCTION_ENTER();
495 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
497 /* deal with medium stuff */
498 for (i = 0; i < MediumArraySize; i++)
499 {
500 if (MediumArray[i] == NdisMedium802_3)
501 {
502 medium_found = TRUE;
503 break;
504 }
505 }
506 if (!medium_found)
507 {
508 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
509 return NDIS_STATUS_UNSUPPORTED_MEDIA;
510 }
511 *SelectedMediumIndex = i;
513 /* Alloc memory for adapter private info */
514 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
515 if (!NT_SUCCESS(status))
516 {
517 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
518 status = NDIS_STATUS_RESOURCES;
519 goto err;
520 }
521 RtlZeroMemory(xi, sizeof(*xi));
522 xi->adapter_handle = MiniportAdapterHandle;
523 xi->rx_target = RX_DFL_MIN_TARGET;
524 xi->rx_min_target = RX_DFL_MIN_TARGET;
525 xi->rx_max_target = RX_MAX_TARGET;
526 xi->inactive = TRUE;
527 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi, 0, 0 /* the last zero is to give the next | something to | with */
528 #ifdef NDIS51_MINIPORT
529 |NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
530 #endif
531 |NDIS_ATTRIBUTE_DESERIALIZE
532 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
533 |NDIS_ATTRIBUTE_BUS_MASTER,
534 NdisInterfaceInternal);
535 xi->multicast_list_size = 0;
536 xi->current_lookahead = MIN_LOOKAHEAD_LENGTH;
538 nrl_length = 0;
539 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
540 NULL, (PUINT)&nrl_length);
541 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
542 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
543 if (status != NDIS_STATUS_SUCCESS)
544 {
545 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
546 return NDIS_STATUS_RESOURCES;
547 }
548 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
549 nrl, (PUINT)&nrl_length);
550 if (status != NDIS_STATUS_SUCCESS)
551 {
552 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
553 return NDIS_STATUS_RESOURCES;
554 }
555 xi->event_channel = 0;
556 xi->config_csum = 1;
557 xi->config_csum_rx_check = 1;
558 xi->config_sg = 1;
559 xi->config_gso = 61440;
560 xi->config_page = NULL;
561 xi->config_rx_interrupt_moderation = 0;
563 for (i = 0; i < nrl->Count; i++)
564 {
565 prd = &nrl->PartialDescriptors[i];
567 switch(prd->Type)
568 {
569 case CmResourceTypeInterrupt:
570 irq_vector = prd->u.Interrupt.Vector;
571 irq_level = (KIRQL)prd->u.Interrupt.Level;
572 irq_mode = (prd->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?NdisInterruptLatched:NdisInterruptLevelSensitive;
573 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x, irq_mode = %s\n", irq_vector, irq_level,
574 (irq_mode == NdisInterruptLatched)?"NdisInterruptLatched":"NdisInterruptLevelSensitive"));
575 break;
576 case CmResourceTypeMemory:
577 if (xi->config_page)
578 {
579 KdPrint(("More than one memory range\n"));
580 return NDIS_STATUS_RESOURCES;
581 }
582 else
583 {
584 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
585 if (!NT_SUCCESS(status))
586 {
587 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
588 NdisFreeMemory(nrl, nrl_length, 0);
589 return NDIS_STATUS_RESOURCES;
590 }
591 }
592 break;
593 }
594 }
595 NdisFreeMemory(nrl, nrl_length, 0);
596 if (!xi->config_page)
597 {
598 KdPrint(("No config page given\n"));
599 return NDIS_STATUS_RESOURCES;
600 }
602 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
604 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
605 &xi->lower_do, NULL, NULL);
606 xi->packet_filter = 0;
608 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
609 NAME_SIZE, xi->dev_desc, &length);
610 if (!NT_SUCCESS(status))
611 {
612 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
613 status = NDIS_STATUS_FAILURE;
614 goto err;
615 }
617 ptr = xi->config_page;
618 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
619 {
620 switch(type)
621 {
622 case XEN_INIT_TYPE_VECTORS:
623 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
624 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
625 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
626 {
627 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
628 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
629 FUNCTION_EXIT();
630 return NDIS_STATUS_FAILURE;
631 }
632 else
633 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
634 break;
635 case XEN_INIT_TYPE_STATE_PTR:
636 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
637 xi->device_state = (PXENPCI_DEVICE_STATE)value;
638 break;
639 case XEN_INIT_TYPE_QEMU_HIDE_FLAGS:
640 qemu_hide_flags_value = PtrToUlong(value);
641 break;
642 case XEN_INIT_TYPE_QEMU_HIDE_FILTER:
643 qemu_hide_filter = TRUE;
644 break;
645 default:
646 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
647 break;
648 }
649 }
651 if ((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) || qemu_hide_filter)
652 xi->inactive = FALSE;
654 xi->power_state = NdisDeviceStateD0;
655 xi->power_workitem = IoAllocateWorkItem(xi->fdo);
657 // now build config page
659 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
660 if (!NT_SUCCESS(status))
661 {
662 KdPrint(("Could not open config in registry (%08x)\n", status));
663 status = NDIS_STATUS_RESOURCES;
664 goto err;
665 }
667 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
668 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
669 if (!NT_SUCCESS(status))
670 {
671 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
672 xi->config_sg = 1;
673 }
674 else
675 {
676 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
677 xi->config_sg = config_param->ParameterData.IntegerData;
678 }
680 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
681 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
682 if (!NT_SUCCESS(status))
683 {
684 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
685 xi->config_gso = 0;
686 }
687 else
688 {
689 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
690 xi->config_gso = config_param->ParameterData.IntegerData;
691 if (xi->config_gso > 61440)
692 {
693 xi->config_gso = 61440;
694 KdPrint(("(clipped to %d)\n", xi->config_gso));
695 }
696 }
698 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
699 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
700 if (!NT_SUCCESS(status))
701 {
702 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
703 xi->config_csum = 1;
704 }
705 else
706 {
707 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
708 xi->config_csum = !!config_param->ParameterData.IntegerData;
709 }
711 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
712 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
713 if (!NT_SUCCESS(status))
714 {
715 KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
716 xi->config_csum_rx_check = 1;
717 }
718 else
719 {
720 KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
721 xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
722 }
724 NdisInitUnicodeString(&config_param_name, L"MTU");
725 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
726 if (!NT_SUCCESS(status))
727 {
728 KdPrint(("Could not read MTU value (%08x)\n", status));
729 xi->config_mtu = 1500;
730 }
731 else
732 {
733 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
734 xi->config_mtu = config_param->ParameterData.IntegerData;
735 }
737 NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
738 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
739 if (!NT_SUCCESS(status))
740 {
741 KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
742 xi->config_rx_interrupt_moderation = 1500;
743 }
744 else
745 {
746 KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
747 xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
748 }
751 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
752 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || ((((PUCHAR)network_address)[0] & 0x03) != 0x02))
753 {
754 KdPrint(("Could not read NetworkAddress value (%08x) or value is invalid\n", status));
755 memset(xi->curr_mac_addr, 0, ETH_ALEN);
756 }
757 else
758 {
759 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
760 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
761 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
762 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
763 }
765 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
767 NdisCloseConfiguration(config_handle);
769 #if 0
770 ptr = xi->config_page;
771 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
772 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
773 #pragma warning(suppress:4054)
774 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
775 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
776 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
777 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
778 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
779 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
780 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
781 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
782 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
783 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
784 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
785 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
786 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
787 __ADD_XEN_INIT_UCHAR(&ptr, 0); /* no pre-connect required */
788 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
789 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
790 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
791 __ADD_XEN_INIT_UCHAR(&ptr, 20);
792 __ADD_XEN_INIT_UCHAR(&ptr, 0);
793 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_SHUTDOWN, NULL, NULL, NULL);
794 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
795 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
796 __ADD_XEN_INIT_UCHAR(&ptr, 50);
797 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
798 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
799 __ADD_XEN_INIT_UCHAR(&ptr, 50);
800 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitialising);
801 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitWait);
802 __ADD_XEN_INIT_UCHAR(&ptr, 50);
803 __ADD_XEN_INIT_UCHAR(&ptr, 0);
804 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
805 #endif
807 status = XenNet_D0Entry(xi);
808 if (!NT_SUCCESS(status))
809 {
810 KdPrint(("Failed to go to D0 (%08x)\n", status));
811 goto err;
812 }
813 return NDIS_STATUS_SUCCESS;
815 err:
816 NdisFreeMemory(xi, 0, 0);
817 *OpenErrorStatus = status;
818 FUNCTION_EXIT_STATUS(status);
819 return status;
820 }
822 VOID
823 XenNet_PnPEventNotify(
824 IN NDIS_HANDLE MiniportAdapterContext,
825 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
826 IN PVOID InformationBuffer,
827 IN ULONG InformationBufferLength
828 )
829 {
830 UNREFERENCED_PARAMETER(MiniportAdapterContext);
831 UNREFERENCED_PARAMETER(PnPEvent);
832 UNREFERENCED_PARAMETER(InformationBuffer);
833 UNREFERENCED_PARAMETER(InformationBufferLength);
835 FUNCTION_ENTER();
836 switch (PnPEvent)
837 {
838 case NdisDevicePnPEventSurpriseRemoved:
839 KdPrint((__DRIVER_NAME " NdisDevicePnPEventSurpriseRemoved\n"));
840 break;
841 case NdisDevicePnPEventPowerProfileChanged :
842 KdPrint((__DRIVER_NAME " NdisDevicePnPEventPowerProfileChanged\n"));
843 break;
844 default:
845 KdPrint((__DRIVER_NAME " %d\n", PnPEvent));
846 break;
847 }
848 FUNCTION_EXIT();
849 }
851 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
852 VOID DDKAPI
853 XenNet_Shutdown(
854 IN NDIS_HANDLE MiniportAdapterContext
855 )
856 {
857 UNREFERENCED_PARAMETER(MiniportAdapterContext);
859 /* remember we are called at >= DIRQL here */
860 FUNCTION_ENTER();
861 FUNCTION_EXIT();
862 }
864 /* Opposite of XenNet_Init */
865 VOID DDKAPI
866 XenNet_Halt(
867 IN NDIS_HANDLE MiniportAdapterContext
868 )
869 {
870 struct xennet_info *xi = MiniportAdapterContext;
872 FUNCTION_ENTER();
873 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
875 XenNet_D0Exit(xi);
877 NdisFreeMemory(xi, 0, 0);
879 FUNCTION_EXIT();
880 }
882 NDIS_STATUS
883 XenNet_D0Exit(struct xennet_info *xi)
884 {
885 FUNCTION_ENTER();
886 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
888 xi->shutting_down = TRUE;
889 KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
891 XenNet_TxShutdown(xi);
892 XenNet_RxShutdown(xi);
894 xi->connected = FALSE;
895 KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
897 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
899 #if 0
900 if (!xi->config_sg)
901 {
902 NdisMFreeMapRegisters(xi->adapter_handle);
903 }
904 #endif
906 FUNCTION_EXIT();
908 return STATUS_SUCCESS;
909 }
911 NDIS_STATUS
912 XenNet_Reset(
913 PBOOLEAN AddressingReset,
914 NDIS_HANDLE MiniportAdapterContext
915 )
916 {
917 UNREFERENCED_PARAMETER(MiniportAdapterContext);
919 *AddressingReset = FALSE;
920 return NDIS_STATUS_SUCCESS;
921 }
923 NTSTATUS
924 DriverEntry(
925 PDRIVER_OBJECT DriverObject,
926 PUNICODE_STRING RegistryPath
927 )
928 {
929 NTSTATUS status;
930 NDIS_HANDLE ndis_wrapper_handle = NULL;
931 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
933 FUNCTION_ENTER();
935 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
937 NdisZeroMemory(&mini_chars, sizeof(mini_chars));
939 KdPrint((__DRIVER_NAME " NdisGetVersion = %x\n", NdisGetVersion()));
941 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
942 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
943 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
944 if (!ndis_wrapper_handle)
945 {
946 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper failed\n"));
947 return NDIS_STATUS_FAILURE;
948 }
949 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper succeeded\n"));
951 /* NDIS 5.1 driver */
952 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
953 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
955 KdPrint((__DRIVER_NAME " MajorNdisVersion = %d, MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
957 mini_chars.HaltHandler = XenNet_Halt;
958 mini_chars.InitializeHandler = XenNet_Init;
959 //mini_chars.ISRHandler = XenNet_InterruptIsr;
960 //mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
961 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
962 mini_chars.ResetHandler = XenNet_Reset;
963 mini_chars.SetInformationHandler = XenNet_SetInformation;
964 /* added in v.4 -- use multiple pkts interface */
965 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
966 mini_chars.SendPacketsHandler = XenNet_SendPackets;
967 /* don't support cancel - no point as packets are never queued for long */
968 //mini_chars.CancelSendPacketsHandler = XenNet_CancelSendPackets;
970 #ifdef NDIS51_MINIPORT
971 /* added in v.5.1 */
972 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
973 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
974 #else
975 // something else here
976 #endif
978 /* set up upper-edge interface */
979 KdPrint((__DRIVER_NAME " about to call NdisMRegisterMiniport\n"));
980 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
981 KdPrint((__DRIVER_NAME " called NdisMRegisterMiniport\n"));
982 if (!NT_SUCCESS(status))
983 {
984 KdPrint((__DRIVER_NAME " NdisMRegisterMiniport failed, status = 0x%x\n", status));
985 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
986 return status;
987 }
989 FUNCTION_EXIT();
991 return status;