1 /* 2 * ReactOS AMD PCNet Driver 3 * 4 * Copyright (C) 2000 Casper Hornstrup <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 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 break; 140 } 141 142 case OID_GEN_MEDIA_SUPPORTED: 143 case OID_GEN_MEDIA_IN_USE: 144 { 145 static const NDIS_MEDIUM Medium = NdisMedium802_3; 146 CopyFrom = (PVOID)&Medium; 147 CopySize = sizeof(NDIS_MEDIUM); 148 break; 149 } 150 151 case OID_GEN_CURRENT_LOOKAHEAD: 152 case OID_GEN_MAXIMUM_LOOKAHEAD: 153 { 154 GenericULONG = 1500; 155 break; 156 } 157 158 case OID_GEN_MAXIMUM_FRAME_SIZE: 159 { 160 /* 161 * The value returned by this OID must be equal to 162 * OID_GEN_MAXIMUM_TOTAL_SIZE - sizeof(ETHERNET_HEADER) 163 * where sizeof(ETHERNET_HEADER) is 14. 164 */ 165 GenericULONG = 1500; 166 break; 167 } 168 169 case OID_GEN_LINK_SPEED: 170 { 171 GenericULONG = Adapter->MediaSpeed * 10000; 172 break; 173 } 174 175 case OID_GEN_TRANSMIT_BUFFER_SPACE: 176 { 177 /* XXX fix me */ 178 GenericULONG = BUFFER_SIZE; 179 break; 180 } 181 182 case OID_GEN_RECEIVE_BUFFER_SPACE: 183 { 184 /* XXX fix me */ 185 GenericULONG = BUFFER_SIZE; 186 break; 187 } 188 189 case OID_GEN_TRANSMIT_BLOCK_SIZE: 190 { 191 GenericULONG = BUFFER_SIZE; 192 break; 193 } 194 195 case OID_GEN_RECEIVE_BLOCK_SIZE: 196 { 197 GenericULONG = BUFFER_SIZE; 198 break; 199 } 200 201 case OID_GEN_VENDOR_ID: 202 { 203 UCHAR *CharPtr = (UCHAR *)&GenericULONG; 204 GenericULONG = 0; 205 /* Read the first three bytes of the permanent MAC address */ 206 NdisRawReadPortUchar(Adapter->PortOffset, CharPtr); 207 NdisRawReadPortUchar(Adapter->PortOffset + 1, CharPtr + 1); 208 NdisRawReadPortUchar(Adapter->PortOffset + 2, CharPtr + 2); 209 break; 210 } 211 212 case OID_GEN_VENDOR_DESCRIPTION: 213 { 214 static UCHAR VendorDesc[] = "ReactOS Team"; 215 CopyFrom = VendorDesc; 216 CopySize = sizeof(VendorDesc); 217 break; 218 } 219 220 case OID_GEN_VENDOR_DRIVER_VERSION: 221 { 222 /* XXX implement me */ 223 GenericULONG = 1; 224 break; 225 } 226 227 case OID_GEN_CURRENT_PACKET_FILTER: 228 { 229 GenericULONG = Adapter->CurrentPacketFilter; 230 break; 231 } 232 233 case OID_GEN_DRIVER_VERSION: 234 { 235 /* NDIS version used by the driver. */ 236 static const USHORT DriverVersion = 237 (NDIS_MINIPORT_MAJOR_VERSION << 8) + NDIS_MINIPORT_MINOR_VERSION; 238 CopyFrom = (PVOID)&DriverVersion; 239 CopySize = sizeof(DriverVersion); 240 break; 241 } 242 243 case OID_GEN_MAXIMUM_TOTAL_SIZE: 244 { 245 /* See comment in OID_GEN_MAXIMUM_FRAME_SIZE. */ 246 GenericULONG = 1514; 247 break; 248 } 249 250 case OID_GEN_PROTOCOL_OPTIONS: 251 { 252 DPRINT("OID_GEN_PROTOCOL_OPTIONS.\n"); 253 Status = NDIS_STATUS_NOT_SUPPORTED; 254 break; 255 } 256 257 case OID_GEN_MAC_OPTIONS: 258 { 259 GenericULONG = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | 260 NDIS_MAC_OPTION_RECEIVE_SERIALIZED | 261 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | 262 NDIS_MAC_OPTION_NO_LOOPBACK; 263 break; 264 } 265 266 case OID_GEN_MEDIA_CONNECT_STATUS: 267 { 268 GenericULONG = (ULONG)NdisMediaStateConnected; /* Adapter->MediaState */ 269 break; 270 } 271 272 case OID_GEN_MAXIMUM_SEND_PACKETS: 273 { 274 GenericULONG = 1; 275 break; 276 } 277 278 case OID_802_3_CURRENT_ADDRESS: 279 case OID_802_3_PERMANENT_ADDRESS: 280 { 281 CopyFrom = (PVOID)&Adapter->InitializationBlockVirt->PADR; 282 CopySize = 6; 283 break; 284 } 285 286 case OID_802_3_MAXIMUM_LIST_SIZE: 287 { 288 GenericULONG = MAX_MULTICAST_ADDRESSES; 289 break; 290 } 291 292 case OID_GEN_XMIT_OK: 293 GenericULONG = Adapter->Statistics.XmtGoodFrames; 294 break; 295 296 case OID_GEN_RCV_OK: 297 GenericULONG = Adapter->Statistics.RcvGoodFrames; 298 break; 299 300 case OID_GEN_XMIT_ERROR: 301 GenericULONG = Adapter->Statistics.XmtRetryErrors + 302 Adapter->Statistics.XmtLossesOfCarrier + 303 Adapter->Statistics.XmtCollisions + 304 Adapter->Statistics.XmtLateCollisions + 305 Adapter->Statistics.XmtExcessiveDeferrals + 306 Adapter->Statistics.XmtBufferUnderflows + 307 Adapter->Statistics.XmtBufferErrors; 308 break; 309 310 case OID_GEN_RCV_ERROR: 311 GenericULONG = Adapter->Statistics.RcvBufferErrors + 312 Adapter->Statistics.RcvCrcErrors + 313 Adapter->Statistics.RcvOverflowErrors + 314 Adapter->Statistics.RcvFramingErrors; 315 break; 316 317 case OID_GEN_RCV_NO_BUFFER: 318 GenericULONG = Adapter->Statistics.RcvBufferErrors + 319 Adapter->Statistics.RcvOverflowErrors; 320 break; 321 322 case OID_GEN_RCV_CRC_ERROR: 323 GenericULONG = Adapter->Statistics.RcvCrcErrors; 324 break; 325 326 case OID_802_3_RCV_ERROR_ALIGNMENT: 327 GenericULONG = Adapter->Statistics.RcvFramingErrors; 328 break; 329 330 case OID_802_3_XMIT_ONE_COLLISION: 331 GenericULONG = Adapter->Statistics.XmtOneRetry; 332 break; 333 334 case OID_802_3_XMIT_MORE_COLLISIONS: 335 GenericULONG = Adapter->Statistics.XmtMoreThanOneRetry; 336 break; 337 338 default: 339 { 340 DPRINT1("Unknown OID\n"); 341 Status = NDIS_STATUS_NOT_SUPPORTED; 342 break; 343 } 344 } 345 346 if (Status == NDIS_STATUS_SUCCESS) 347 { 348 if (CopySize > InformationBufferLength) 349 { 350 *BytesNeeded = CopySize; 351 *BytesWritten = 0; 352 Status = NDIS_STATUS_INVALID_LENGTH; 353 } 354 else 355 { 356 NdisMoveMemory(InformationBuffer, CopyFrom, CopySize); 357 *BytesWritten = CopySize; 358 *BytesNeeded = CopySize; 359 } 360 } 361 else 362 { 363 *BytesWritten = 0; 364 *BytesNeeded = 0; 365 } 366 367 NdisReleaseSpinLock(&Adapter->Lock); 368 369 DPRINT("Leaving. Status is 0x%x\n", Status); 370 371 return Status; 372 } 373 374 NDIS_STATUS 375 NTAPI 376 MiniportSetInformation( 377 IN NDIS_HANDLE MiniportAdapterContext, 378 IN NDIS_OID Oid, 379 IN PVOID InformationBuffer, 380 IN ULONG InformationBufferLength, 381 OUT PULONG BytesRead, 382 OUT PULONG BytesNeeded) 383 /* 384 * FUNCTION: Set a miniport variable (OID) 385 * ARGUMENTS: 386 * MiniportAdapterContext: context originally passed into NdisMSetAttributes 387 * Oid: the variable being set 388 * InformationBuffer: the data to set the variable to 389 * InformationBufferLength: number of bytes in InformationBuffer 390 * BytesRead: number of bytes read by us out of the buffer 391 * BytesNeeded: number of bytes required to satisfy the request if InformationBufferLength 392 * is insufficient 393 * RETURNS: 394 * NDIS_STATUS_SUCCESS on all requests 395 * NOTES: 396 * - Called by NDIS at DISPATCH_LEVEL 397 * - verify buffer space as mentioned in previous function notes 398 */ 399 { 400 ULONG GenericULONG; 401 NDIS_STATUS Status = NDIS_STATUS_SUCCESS; 402 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; 403 404 ASSERT(Adapter); 405 406 DPRINT("Called, OID 0x%x\n", Oid); 407 408 NdisAcquireSpinLock(&Adapter->Lock); 409 410 switch (Oid) 411 { 412 case OID_GEN_CURRENT_PACKET_FILTER: 413 { 414 /* Verify length */ 415 if (InformationBufferLength < sizeof(ULONG)) 416 { 417 *BytesRead = 0; 418 *BytesNeeded = sizeof(ULONG); 419 Status = NDIS_STATUS_INVALID_LENGTH; 420 break; 421 } 422 423 NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG)); 424 425 /* Check for properties the driver don't support */ 426 if (GenericULONG & 427 (NDIS_PACKET_TYPE_ALL_FUNCTIONAL | 428 NDIS_PACKET_TYPE_FUNCTIONAL | 429 NDIS_PACKET_TYPE_GROUP | 430 NDIS_PACKET_TYPE_MAC_FRAME | 431 NDIS_PACKET_TYPE_SMT | 432 NDIS_PACKET_TYPE_SOURCE_ROUTING) 433 ) 434 { 435 *BytesRead = sizeof(ULONG); 436 *BytesNeeded = 0; 437 Status = NDIS_STATUS_NOT_SUPPORTED; 438 break; 439 } 440 441 Adapter->CurrentPacketFilter = GenericULONG; 442 443 /* FIXME: Set filter on hardware */ 444 445 break; 446 } 447 448 case OID_GEN_CURRENT_LOOKAHEAD: 449 { 450 /* Verify length */ 451 if (InformationBufferLength < sizeof(ULONG)) 452 { 453 *BytesRead = 0; 454 *BytesNeeded = sizeof(ULONG); 455 Status = NDIS_STATUS_INVALID_LENGTH; 456 break; 457 } 458 459 NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG)); 460 461 if (GenericULONG > 1500) 462 Status = NDIS_STATUS_INVALID_DATA; 463 else 464 Adapter->CurrentLookaheadSize = GenericULONG; 465 466 break; 467 } 468 469 case OID_802_3_MULTICAST_LIST: 470 { 471 /* Verify length. Must be multiple of hardware address length */ 472 if ((InformationBufferLength % 6) != 0) 473 { 474 *BytesRead = 0; 475 *BytesNeeded = InformationBufferLength + (InformationBufferLength % 6); 476 Status = NDIS_STATUS_INVALID_LENGTH; 477 break; 478 } 479 480 ASSERT((InformationBufferLength / 6) <= MAX_MULTICAST_ADDRESSES); 481 482 /* Set new multicast address list */ 483 //NdisMoveMemory(Adapter->Addresses, InformationBuffer, InformationBufferLength); 484 485 /* Update hardware */ 486 Status = MiSetMulticast(Adapter, InformationBuffer, InformationBufferLength / 6); 487 488 break; 489 } 490 491 default: 492 { 493 DPRINT1("Invalid object ID (0x%X).\n", Oid); 494 *BytesRead = 0; 495 *BytesNeeded = 0; 496 Status = NDIS_STATUS_NOT_SUPPORTED; 497 break; 498 } 499 } 500 501 if (Status == NDIS_STATUS_SUCCESS) 502 { 503 *BytesRead = InformationBufferLength; 504 *BytesNeeded = 0; 505 } 506 507 NdisReleaseSpinLock(&Adapter->Lock); 508 509 DPRINT("Leaving. Status (0x%X).\n", Status); 510 511 return Status; 512 } 513