[PCNET]
[reactos.git] / drivers / network / dd / pcnet / requests.c
1 /*
2 * ReactOS AMD PCNet Driver
3 *
4 * Copyright (C) 2000 Casper Hornstroup <chorns@users.sourceforge.net>
5 * Copyright (C) 2003 Vizzini <vizzini@plasmic.com>
6 * Copyright (C) 2004 Filip Navara <navaraf@reactos.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * PROGRAMMERS:
23 * Vizzini (vizzini@plasmic.com),
24 * borrowed very heavily from the ReactOS ne2000 driver by
25 * Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISIONS:
27 * 14-Sep-2003 vizzini - Created
28 * 17-Oct-2004 navaraf - Add multicast support.
29 * - Add media state detection support.
30 * - Protect the adapter context with spinlock
31 * and move code talking to card to inside
32 * NdisMSynchronizeWithInterrupt calls where
33 * necessary.
34 */
35
36 #include "pcnet.h"
37
38 #define NDEBUG
39 #include <debug.h>
40
41 /* List of supported OIDs */
42 static ULONG MiniportOIDList[] =
43 {
44 OID_GEN_SUPPORTED_LIST,
45 OID_GEN_HARDWARE_STATUS,
46 OID_GEN_MEDIA_SUPPORTED,
47 OID_GEN_MEDIA_IN_USE,
48 OID_GEN_MAXIMUM_LOOKAHEAD,
49 OID_GEN_MAXIMUM_FRAME_SIZE,
50 OID_GEN_LINK_SPEED,
51 OID_GEN_TRANSMIT_BUFFER_SPACE,
52 OID_GEN_RECEIVE_BUFFER_SPACE,
53 OID_GEN_TRANSMIT_BLOCK_SIZE,
54 OID_GEN_RECEIVE_BLOCK_SIZE,
55 OID_GEN_VENDOR_ID,
56 OID_GEN_VENDOR_DESCRIPTION,
57 OID_GEN_VENDOR_DRIVER_VERSION,
58 OID_GEN_CURRENT_PACKET_FILTER,
59 OID_GEN_CURRENT_LOOKAHEAD,
60 OID_GEN_DRIVER_VERSION,
61 OID_GEN_MAXIMUM_TOTAL_SIZE,
62 OID_GEN_PROTOCOL_OPTIONS,
63 OID_GEN_MAC_OPTIONS,
64 OID_GEN_MEDIA_CONNECT_STATUS,
65 OID_GEN_MAXIMUM_SEND_PACKETS,
66 OID_GEN_XMIT_OK,
67 OID_GEN_RCV_OK,
68 OID_GEN_XMIT_ERROR,
69 OID_GEN_RCV_ERROR,
70 OID_GEN_RCV_NO_BUFFER,
71 OID_GEN_RCV_CRC_ERROR,
72 OID_802_3_PERMANENT_ADDRESS,
73 OID_802_3_CURRENT_ADDRESS,
74 OID_802_3_MULTICAST_LIST,
75 OID_802_3_MAXIMUM_LIST_SIZE,
76 OID_802_3_MAC_OPTIONS,
77 OID_802_3_RCV_ERROR_ALIGNMENT,
78 OID_802_3_XMIT_ONE_COLLISION,
79 OID_802_3_XMIT_MORE_COLLISIONS
80 };
81
82 \f
83 NDIS_STATUS
84 NTAPI
85 MiniportQueryInformation(
86 IN NDIS_HANDLE MiniportAdapterContext,
87 IN NDIS_OID Oid,
88 IN PVOID InformationBuffer,
89 IN ULONG InformationBufferLength,
90 OUT PULONG BytesWritten,
91 OUT PULONG BytesNeeded)
92 /*
93 * FUNCTION: Query an OID from the driver
94 * ARGUMENTS:
95 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
96 * Oid: OID NDIS is querying
97 * InformationBuffer: pointer to buffer into which to write the results of the query
98 * InformationBufferLength: size in bytes of InformationBuffer
99 * BytesWritten: number of bytes written into InformationBuffer in response to the query
100 * BytesNeeded: number of bytes needed to answer the query
101 * RETURNS:
102 * NDIS_STATUS_SUCCESS on all queries
103 * NOTES:
104 * - Called by NDIS at DISPATCH_LEVEL
105 * - If InformationBufferLength is insufficient to store the results, return the amount
106 * needed in BytesNeeded and return NDIS_STATUS_INVALID_LENGTH
107 * TODO:
108 * - Update to verify input buffer & size and return insufficient buffer codes
109 */
110 {
111 NDIS_STATUS Status;
112 PVOID CopyFrom;
113 UINT CopySize;
114 ULONG GenericULONG;
115 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
116
117 DPRINT("Called. OID 0x%x\n", Oid);
118
119 ASSERT(Adapter);
120
121 NdisAcquireSpinLock(&Adapter->Lock);
122
123 Status = NDIS_STATUS_SUCCESS;
124 CopyFrom = (PVOID)&GenericULONG;
125 CopySize = sizeof(ULONG);
126
127 switch (Oid)
128 {
129 case OID_GEN_SUPPORTED_LIST:
130 {
131 CopyFrom = (PVOID)&MiniportOIDList;
132 CopySize = sizeof(MiniportOIDList);
133 break;
134 }
135
136 case OID_GEN_HARDWARE_STATUS:
137 {
138 GenericULONG = (ULONG)NdisHardwareStatusReady;
139 /* ((Adapter->MediaState == NdisMediaStateConnected) ? NdisHardwareStatusReady : NdisHardwareStatusNotReady); */
140 break;
141 }
142
143 case OID_GEN_MEDIA_SUPPORTED:
144 case OID_GEN_MEDIA_IN_USE:
145 {
146 static const NDIS_MEDIUM Medium = NdisMedium802_3;
147 CopyFrom = (PVOID)&Medium;
148 CopySize = sizeof(NDIS_MEDIUM);
149 break;
150 }
151
152 case OID_GEN_CURRENT_LOOKAHEAD:
153 case OID_GEN_MAXIMUM_LOOKAHEAD:
154 {
155 GenericULONG = 1500;
156 break;
157 }
158
159 case OID_GEN_MAXIMUM_FRAME_SIZE:
160 {
161 /*
162 * The value returned by this OID must be equal to
163 * OID_GEN_MAXIMUM_TOTAL_SIZE - sizeof(ETHERNET_HEADER)
164 * where sizeof(ETHERNET_HEADER) is 14.
165 */
166 GenericULONG = 1500;
167 break;
168 }
169
170 case OID_GEN_LINK_SPEED:
171 {
172 GenericULONG = Adapter->MediaSpeed * 10000;
173 break;
174 }
175
176 case OID_GEN_TRANSMIT_BUFFER_SPACE:
177 {
178 /* XXX fix me */
179 GenericULONG = BUFFER_SIZE;
180 break;
181 }
182
183 case OID_GEN_RECEIVE_BUFFER_SPACE:
184 {
185 /* XXX fix me */
186 GenericULONG = BUFFER_SIZE;
187 break;
188 }
189
190 case OID_GEN_TRANSMIT_BLOCK_SIZE:
191 {
192 GenericULONG = BUFFER_SIZE;
193 break;
194 }
195
196 case OID_GEN_RECEIVE_BLOCK_SIZE:
197 {
198 GenericULONG = BUFFER_SIZE;
199 break;
200 }
201
202 case OID_GEN_VENDOR_ID:
203 {
204 UCHAR *CharPtr = (UCHAR *)&GenericULONG;
205 GenericULONG = 0;
206 /* Read the first three bytes of the permanent MAC address */
207 NdisRawReadPortUchar(Adapter->PortOffset, CharPtr);
208 NdisRawReadPortUchar(Adapter->PortOffset + 1, CharPtr + 1);
209 NdisRawReadPortUchar(Adapter->PortOffset + 2, CharPtr + 2);
210 break;
211 }
212
213 case OID_GEN_VENDOR_DESCRIPTION:
214 {
215 static UCHAR VendorDesc[] = "ReactOS Team";
216 CopyFrom = VendorDesc;
217 CopySize = sizeof(VendorDesc);
218 break;
219 }
220
221 case OID_GEN_VENDOR_DRIVER_VERSION:
222 {
223 /* XXX implement me */
224 GenericULONG = 1;
225 break;
226 }
227
228 case OID_GEN_CURRENT_PACKET_FILTER:
229 {
230 GenericULONG = Adapter->CurrentPacketFilter;
231 break;
232 }
233
234 case OID_GEN_DRIVER_VERSION:
235 {
236 /* NDIS version used by the driver. */
237 static const USHORT DriverVersion =
238 (NDIS_MINIPORT_MAJOR_VERSION << 8) + NDIS_MINIPORT_MINOR_VERSION;
239 CopyFrom = (PVOID)&DriverVersion;
240 CopySize = sizeof(DriverVersion);
241 break;
242 }
243
244 case OID_GEN_MAXIMUM_TOTAL_SIZE:
245 {
246 /* See comment in OID_GEN_MAXIMUM_FRAME_SIZE. */
247 GenericULONG = 1514;
248 break;
249 }
250
251 case OID_GEN_PROTOCOL_OPTIONS:
252 {
253 DPRINT("OID_GEN_PROTOCOL_OPTIONS.\n");
254 Status = NDIS_STATUS_NOT_SUPPORTED;
255 break;
256 }
257
258 case OID_GEN_MAC_OPTIONS:
259 {
260 GenericULONG = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
261 NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
262 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
263 NDIS_MAC_OPTION_NO_LOOPBACK;
264 break;
265 }
266
267 case OID_GEN_MEDIA_CONNECT_STATUS:
268 {
269 GenericULONG = (ULONG)NdisMediaStateConnected; /* Adapter->MediaState */
270 break;
271 }
272
273 case OID_GEN_MAXIMUM_SEND_PACKETS:
274 {
275 GenericULONG = 1;
276 break;
277 }
278
279 case OID_802_3_CURRENT_ADDRESS:
280 case OID_802_3_PERMANENT_ADDRESS:
281 {
282 CopyFrom = (PVOID)&Adapter->InitializationBlockVirt->PADR;
283 CopySize = 6;
284 break;
285 }
286
287 case OID_802_3_MAXIMUM_LIST_SIZE:
288 {
289 GenericULONG = MAX_MULTICAST_ADDRESSES;
290 break;
291 }
292
293 case OID_GEN_XMIT_OK:
294 GenericULONG = Adapter->Statistics.XmtGoodFrames;
295 break;
296
297 case OID_GEN_RCV_OK:
298 GenericULONG = Adapter->Statistics.RcvGoodFrames;
299 break;
300
301 case OID_GEN_XMIT_ERROR:
302 GenericULONG = Adapter->Statistics.XmtRetryErrors +
303 Adapter->Statistics.XmtLossesOfCarrier +
304 Adapter->Statistics.XmtCollisions +
305 Adapter->Statistics.XmtLateCollisions +
306 Adapter->Statistics.XmtExcessiveDefferals +
307 Adapter->Statistics.XmtBufferUnderflows +
308 Adapter->Statistics.XmtBufferErrors;
309 break;
310
311 case OID_GEN_RCV_ERROR:
312 GenericULONG = Adapter->Statistics.RcvBufferErrors +
313 Adapter->Statistics.RcvCrcErrors +
314 Adapter->Statistics.RcvOverflowErrors +
315 Adapter->Statistics.RcvFramingErrors;
316 break;
317
318 case OID_GEN_RCV_NO_BUFFER:
319 GenericULONG = Adapter->Statistics.RcvBufferErrors +
320 Adapter->Statistics.RcvOverflowErrors;
321 break;
322
323 case OID_GEN_RCV_CRC_ERROR:
324 GenericULONG = Adapter->Statistics.RcvCrcErrors;
325 break;
326
327 case OID_802_3_RCV_ERROR_ALIGNMENT:
328 GenericULONG = Adapter->Statistics.RcvFramingErrors;
329 break;
330
331 case OID_802_3_XMIT_ONE_COLLISION:
332 GenericULONG = Adapter->Statistics.XmtOneRetry;
333 break;
334
335 case OID_802_3_XMIT_MORE_COLLISIONS:
336 GenericULONG = Adapter->Statistics.XmtMoreThanOneRetry;
337 break;
338
339 default:
340 {
341 DPRINT1("Unknown OID\n");
342 Status = NDIS_STATUS_NOT_SUPPORTED;
343 break;
344 }
345 }
346
347 if (Status == NDIS_STATUS_SUCCESS)
348 {
349 if (CopySize > InformationBufferLength)
350 {
351 *BytesNeeded = CopySize;
352 *BytesWritten = 0;
353 Status = NDIS_STATUS_INVALID_LENGTH;
354 }
355 else
356 {
357 NdisMoveMemory(InformationBuffer, CopyFrom, CopySize);
358 *BytesWritten = CopySize;
359 *BytesNeeded = CopySize;
360 }
361 }
362 else
363 {
364 *BytesWritten = 0;
365 *BytesNeeded = 0;
366 }
367
368 NdisReleaseSpinLock(&Adapter->Lock);
369
370 DPRINT("Leaving. Status is 0x%x\n", Status);
371
372 return Status;
373 }
374
375 NDIS_STATUS
376 NTAPI
377 MiniportSetInformation(
378 IN NDIS_HANDLE MiniportAdapterContext,
379 IN NDIS_OID Oid,
380 IN PVOID InformationBuffer,
381 IN ULONG InformationBufferLength,
382 OUT PULONG BytesRead,
383 OUT PULONG BytesNeeded)
384 /*
385 * FUNCTION: Set a miniport variable (OID)
386 * ARGUMENTS:
387 * MiniportAdapterContext: context originally passed into NdisMSetAttributes
388 * Oid: the variable being set
389 * InformationBuffer: the data to set the variable to
390 * InformationBufferLength: number of bytes in InformationBuffer
391 * BytesRead: number of bytes read by us out of the buffer
392 * BytesNeeded: number of bytes required to satisfy the request if InformationBufferLength
393 * is insufficient
394 * RETURNS:
395 * NDIS_STATUS_SUCCESS on all requests
396 * NOTES:
397 * - Called by NDIS at DISPATCH_LEVEL
398 * - verify buffer space as mentioned in previous function notes
399 */
400 {
401 ULONG GenericULONG;
402 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
403 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
404
405 ASSERT(Adapter);
406
407 DPRINT("Called, OID 0x%x\n", Oid);
408
409 NdisAcquireSpinLock(&Adapter->Lock);
410
411 switch (Oid)
412 {
413 case OID_GEN_CURRENT_PACKET_FILTER:
414 {
415 /* Verify length */
416 if (InformationBufferLength < sizeof(ULONG))
417 {
418 *BytesRead = 0;
419 *BytesNeeded = sizeof(ULONG);
420 Status = NDIS_STATUS_INVALID_LENGTH;
421 break;
422 }
423
424 NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
425
426 /* Check for properties the driver don't support */
427 if (GenericULONG &
428 (NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
429 NDIS_PACKET_TYPE_FUNCTIONAL |
430 NDIS_PACKET_TYPE_GROUP |
431 NDIS_PACKET_TYPE_MAC_FRAME |
432 NDIS_PACKET_TYPE_SMT |
433 NDIS_PACKET_TYPE_SOURCE_ROUTING)
434 )
435 {
436 *BytesRead = sizeof(ULONG);
437 *BytesNeeded = 0;
438 Status = NDIS_STATUS_NOT_SUPPORTED;
439 break;
440 }
441
442 Adapter->CurrentPacketFilter = GenericULONG;
443
444 /* FIXME: Set filter on hardware */
445
446 break;
447 }
448
449 case OID_GEN_CURRENT_LOOKAHEAD:
450 {
451 /* Verify length */
452 if (InformationBufferLength < sizeof(ULONG))
453 {
454 *BytesRead = 0;
455 *BytesNeeded = sizeof(ULONG);
456 Status = NDIS_STATUS_INVALID_LENGTH;
457 break;
458 }
459
460 NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
461
462 if (GenericULONG > 1500)
463 Status = NDIS_STATUS_INVALID_DATA;
464 else
465 Adapter->CurrentLookaheadSize = GenericULONG;
466
467 break;
468 }
469
470 case OID_802_3_MULTICAST_LIST:
471 {
472 /* Verify length. Must be multiple of hardware address length */
473 if ((InformationBufferLength % 6) != 0)
474 {
475 *BytesRead = 0;
476 *BytesNeeded = InformationBufferLength + (InformationBufferLength % 6);
477 Status = NDIS_STATUS_INVALID_LENGTH;
478 break;
479 }
480
481 ASSERT((InformationBufferLength / 6) <= MAX_MULTICAST_ADDRESSES);
482
483 /* Set new multicast address list */
484 //NdisMoveMemory(Adapter->Addresses, InformationBuffer, InformationBufferLength);
485
486 /* Update hardware */
487 Status = MiSetMulticast(Adapter, InformationBuffer, InformationBufferLength / 6);
488
489 break;
490 }
491
492 default:
493 {
494 DPRINT1("Invalid object ID (0x%X).\n", Oid);
495 *BytesRead = 0;
496 *BytesNeeded = 0;
497 Status = NDIS_STATUS_NOT_SUPPORTED;
498 break;
499 }
500 }
501
502 if (Status == NDIS_STATUS_SUCCESS)
503 {
504 *BytesRead = InformationBufferLength;
505 *BytesNeeded = 0;
506 }
507
508 NdisReleaseSpinLock(&Adapter->Lock);
509
510 DPRINT("Leaving. Status (0x%X).\n", Status);
511
512 return Status;
513 }
514