1
0

sm91c1.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. sm91c1.c
  5. Abstract:
  6. This module implements support for the driver portion of the SMSC91C111
  7. LAN Ethernet Controller.
  8. Author:
  9. Chris Stevens 16-Apr-2014
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/net/netdrv.h>
  18. #include "sm91c1.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // ------------------------------------------------------ Data Type Definitions
  24. //
  25. //
  26. // ----------------------------------------------- Internal Function Prototypes
  27. //
  28. KSTATUS
  29. Sm91c1AddDevice (
  30. PVOID Driver,
  31. PSTR DeviceId,
  32. PSTR ClassId,
  33. PSTR CompatibleIds,
  34. PVOID DeviceToken
  35. );
  36. VOID
  37. Sm91c1DispatchStateChange (
  38. PIRP Irp,
  39. PVOID DeviceContext,
  40. PVOID IrpContext
  41. );
  42. VOID
  43. Sm91c1DispatchOpen (
  44. PIRP Irp,
  45. PVOID DeviceContext,
  46. PVOID IrpContext
  47. );
  48. VOID
  49. Sm91c1DispatchClose (
  50. PIRP Irp,
  51. PVOID DeviceContext,
  52. PVOID IrpContext
  53. );
  54. VOID
  55. Sm91c1DispatchIo (
  56. PIRP Irp,
  57. PVOID DeviceContext,
  58. PVOID IrpContext
  59. );
  60. VOID
  61. Sm91c1DispatchSystemControl (
  62. PIRP Irp,
  63. PVOID DeviceContext,
  64. PVOID IrpContext
  65. );
  66. VOID
  67. Sm91c1DestroyLink (
  68. PVOID DeviceContext
  69. );
  70. KSTATUS
  71. Sm91c1pProcessResourceRequirements (
  72. PIRP Irp
  73. );
  74. KSTATUS
  75. Sm91c1pStartDevice (
  76. PIRP Irp,
  77. PSM91C1_DEVICE Device
  78. );
  79. //
  80. // -------------------------------------------------------------------- Globals
  81. //
  82. PDRIVER Sm91c1Driver = NULL;
  83. //
  84. // ------------------------------------------------------------------ Functions
  85. //
  86. KSTATUS
  87. DriverEntry (
  88. PDRIVER Driver
  89. )
  90. /*++
  91. Routine Description:
  92. This routine is the entry point for the SMSC91C111 driver. It registers its
  93. other dispatch functions, and performs driver-wide initialization.
  94. Arguments:
  95. Driver - Supplies a pointer to the driver object.
  96. Return Value:
  97. STATUS_SUCCESS on success.
  98. Failure code on error.
  99. --*/
  100. {
  101. DRIVER_FUNCTION_TABLE FunctionTable;
  102. KSTATUS Status;
  103. Sm91c1Driver = Driver;
  104. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  105. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  106. FunctionTable.AddDevice = Sm91c1AddDevice;
  107. FunctionTable.DispatchStateChange = Sm91c1DispatchStateChange;
  108. FunctionTable.DispatchOpen = Sm91c1DispatchOpen;
  109. FunctionTable.DispatchClose = Sm91c1DispatchClose;
  110. FunctionTable.DispatchIo = Sm91c1DispatchIo;
  111. FunctionTable.DispatchSystemControl = Sm91c1DispatchSystemControl;
  112. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  113. return Status;
  114. }
  115. KSTATUS
  116. Sm91c1AddDevice (
  117. PVOID Driver,
  118. PSTR DeviceId,
  119. PSTR ClassId,
  120. PSTR CompatibleIds,
  121. PVOID DeviceToken
  122. )
  123. /*++
  124. Routine Description:
  125. This routine is called when a device is detected for which the SMSC91C111
  126. driver acts as the function driver. The driver will attach itself to the
  127. stack.
  128. Arguments:
  129. Driver - Supplies a pointer to the driver being called.
  130. DeviceId - Supplies a pointer to a string with the device ID.
  131. ClassId - Supplies a pointer to a string containing the device's class ID.
  132. CompatibleIds - Supplies a pointer to a string containing device IDs
  133. that would be compatible with this device.
  134. DeviceToken - Supplies an opaque token that the driver can use to identify
  135. the device in the system. This token should be used when attaching to
  136. the stack.
  137. Return Value:
  138. STATUS_SUCCESS on success.
  139. Failure code if the driver was unsuccessful in attaching itself.
  140. --*/
  141. {
  142. PSM91C1_DEVICE Device;
  143. KSTATUS Status;
  144. Device = MmAllocateNonPagedPool(sizeof(SM91C1_DEVICE),
  145. SM91C1_ALLOCATION_TAG);
  146. if (Device == NULL) {
  147. Status = STATUS_INSUFFICIENT_RESOURCES;
  148. goto AddDeviceEnd;
  149. }
  150. RtlZeroMemory(Device, sizeof(SM91C1_DEVICE));
  151. Device->InterruptHandle = INVALID_HANDLE;
  152. Device->OsDevice = DeviceToken;
  153. Status = IoAttachDriverToDevice(Driver, DeviceToken, Device);
  154. if (!KSUCCESS(Status)) {
  155. goto AddDeviceEnd;
  156. }
  157. AddDeviceEnd:
  158. if (!KSUCCESS(Status)) {
  159. if (Device != NULL) {
  160. MmFreeNonPagedPool(Device);
  161. Device = NULL;
  162. }
  163. }
  164. return Status;
  165. }
  166. VOID
  167. Sm91c1DispatchStateChange (
  168. PIRP Irp,
  169. PVOID DeviceContext,
  170. PVOID IrpContext
  171. )
  172. /*++
  173. Routine Description:
  174. This routine handles State Change IRPs.
  175. Arguments:
  176. Irp - Supplies a pointer to the I/O request packet.
  177. DeviceContext - Supplies the context pointer supplied by the driver when it
  178. attached itself to the driver stack. Presumably this pointer contains
  179. driver-specific device context.
  180. IrpContext - Supplies the context pointer supplied by the driver when
  181. the IRP was created.
  182. Return Value:
  183. None.
  184. --*/
  185. {
  186. KSTATUS Status;
  187. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  188. if (Irp->Direction == IrpUp) {
  189. switch (Irp->MinorCode) {
  190. case IrpMinorQueryResources:
  191. Status = Sm91c1pProcessResourceRequirements(Irp);
  192. if (!KSUCCESS(Status)) {
  193. IoCompleteIrp(Sm91c1Driver, Irp, Status);
  194. }
  195. break;
  196. case IrpMinorStartDevice:
  197. Status = Sm91c1pStartDevice(Irp, DeviceContext);
  198. if (!KSUCCESS(Status)) {
  199. IoCompleteIrp(Sm91c1Driver, Irp, Status);
  200. }
  201. break;
  202. default:
  203. break;
  204. }
  205. }
  206. return;
  207. }
  208. VOID
  209. Sm91c1DispatchOpen (
  210. PIRP Irp,
  211. PVOID DeviceContext,
  212. PVOID IrpContext
  213. )
  214. /*++
  215. Routine Description:
  216. This routine handles Open IRPs.
  217. Arguments:
  218. Irp - Supplies a pointer to the I/O request packet.
  219. DeviceContext - Supplies the context pointer supplied by the driver when it
  220. attached itself to the driver stack. Presumably this pointer contains
  221. driver-specific device context.
  222. IrpContext - Supplies the context pointer supplied by the driver when
  223. the IRP was created.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. return;
  229. }
  230. VOID
  231. Sm91c1DispatchClose (
  232. PIRP Irp,
  233. PVOID DeviceContext,
  234. PVOID IrpContext
  235. )
  236. /*++
  237. Routine Description:
  238. This routine handles Close IRPs.
  239. Arguments:
  240. Irp - Supplies a pointer to the I/O request packet.
  241. DeviceContext - Supplies the context pointer supplied by the driver when it
  242. attached itself to the driver stack. Presumably this pointer contains
  243. driver-specific device context.
  244. IrpContext - Supplies the context pointer supplied by the driver when
  245. the IRP was created.
  246. Return Value:
  247. None.
  248. --*/
  249. {
  250. return;
  251. }
  252. VOID
  253. Sm91c1DispatchIo (
  254. PIRP Irp,
  255. PVOID DeviceContext,
  256. PVOID IrpContext
  257. )
  258. /*++
  259. Routine Description:
  260. This routine handles I/O IRPs.
  261. Arguments:
  262. Irp - Supplies a pointer to the I/O request packet.
  263. DeviceContext - Supplies the context pointer supplied by the driver when it
  264. attached itself to the driver stack. Presumably this pointer contains
  265. driver-specific device context.
  266. IrpContext - Supplies the context pointer supplied by the driver when
  267. the IRP was created.
  268. Return Value:
  269. None.
  270. --*/
  271. {
  272. return;
  273. }
  274. VOID
  275. Sm91c1DispatchSystemControl (
  276. PIRP Irp,
  277. PVOID DeviceContext,
  278. PVOID IrpContext
  279. )
  280. /*++
  281. Routine Description:
  282. This routine handles System Control IRPs.
  283. Arguments:
  284. Irp - Supplies a pointer to the I/O request packet.
  285. DeviceContext - Supplies the context pointer supplied by the driver when it
  286. attached itself to the driver stack. Presumably this pointer contains
  287. driver-specific device context.
  288. IrpContext - Supplies the context pointer supplied by the driver when
  289. the IRP was created.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. PSM91C1_DEVICE Device;
  295. PSYSTEM_CONTROL_DEVICE_INFORMATION DeviceInformationRequest;
  296. KSTATUS Status;
  297. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  298. Device = DeviceContext;
  299. if (Irp->Direction == IrpDown) {
  300. switch (Irp->MinorCode) {
  301. case IrpMinorSystemControlDeviceInformation:
  302. DeviceInformationRequest = Irp->U.SystemControl.SystemContext;
  303. Status = NetGetSetLinkDeviceInformation(
  304. Device->NetworkLink,
  305. &(DeviceInformationRequest->Uuid),
  306. DeviceInformationRequest->Data,
  307. &(DeviceInformationRequest->DataSize),
  308. DeviceInformationRequest->Set);
  309. IoCompleteIrp(Sm91c1Driver, Irp, Status);
  310. break;
  311. default:
  312. break;
  313. }
  314. }
  315. return;
  316. }
  317. KSTATUS
  318. Sm91c1pAddNetworkDevice (
  319. PSM91C1_DEVICE Device
  320. )
  321. /*++
  322. Routine Description:
  323. This routine adds the device to core networking's available links.
  324. Arguments:
  325. Device - Supplies a pointer to the device to add.
  326. Return Value:
  327. Status code.
  328. --*/
  329. {
  330. NET_LINK_PROPERTIES Properties;
  331. KSTATUS Status;
  332. if (Device->NetworkLink != NULL) {
  333. Status = STATUS_SUCCESS;
  334. goto AddNetworkDeviceEnd;
  335. }
  336. //
  337. // Add a link to the core networking library.
  338. //
  339. RtlZeroMemory(&Properties, sizeof(NET_LINK_PROPERTIES));
  340. Properties.Version = NET_LINK_PROPERTIES_VERSION;
  341. Properties.TransmitAlignment = 0;
  342. Properties.Device = Device->OsDevice;
  343. Properties.DeviceContext = Device;
  344. Properties.PacketSizeInformation.MaxPacketSize = SM91C1_MAX_PACKET_SIZE;
  345. Properties.PacketSizeInformation.HeaderSize = SM91C1_PACKET_HEADER_SIZE;
  346. Properties.PacketSizeInformation.FooterSize = SM91C1_PACKET_FOOTER_SIZE;
  347. Properties.DataLinkType = NetDomainEthernet;
  348. Properties.MaxPhysicalAddress = MAX_ULONG;
  349. Properties.PhysicalAddress.Domain = NetDomainEthernet;
  350. RtlCopyMemory(&(Properties.PhysicalAddress.Address),
  351. &(Device->MacAddress),
  352. sizeof(Device->MacAddress));
  353. Properties.Interface.Send = Sm91c1Send;
  354. Properties.Interface.GetSetInformation = Sm91c1GetSetInformation;
  355. Properties.Interface.DestroyLink = Sm91c1DestroyLink;
  356. Status = NetAddLink(&Properties, &(Device->NetworkLink));
  357. if (!KSUCCESS(Status)) {
  358. goto AddNetworkDeviceEnd;
  359. }
  360. AddNetworkDeviceEnd:
  361. if (!KSUCCESS(Status)) {
  362. if (Device->NetworkLink != NULL) {
  363. NetRemoveLink(Device->NetworkLink);
  364. Device->NetworkLink = NULL;
  365. }
  366. }
  367. return Status;
  368. }
  369. VOID
  370. Sm91c1DestroyLink (
  371. PVOID DeviceContext
  372. )
  373. /*++
  374. Routine Description:
  375. This routine notifies the device layer that the networking core is in the
  376. process of destroying the link and will no longer call into the device for
  377. this link. This allows the device layer to release any context that was
  378. supporting the device link interface.
  379. Arguments:
  380. DeviceContext - Supplies a pointer to the device context associated with
  381. the link being destroyed.
  382. Return Value:
  383. None.
  384. --*/
  385. {
  386. return;
  387. }
  388. //
  389. // --------------------------------------------------------- Internal Functions
  390. //
  391. KSTATUS
  392. Sm91c1pProcessResourceRequirements (
  393. PIRP Irp
  394. )
  395. /*++
  396. Routine Description:
  397. This routine filters through the resource requirements presented by the
  398. bus for an SMSC91C111 LAN controller. It adds an interrupt vector
  399. requirement for any interrupt line requested.
  400. Arguments:
  401. Irp - Supplies a pointer to the I/O request packet.
  402. Return Value:
  403. Status code.
  404. --*/
  405. {
  406. PRESOURCE_CONFIGURATION_LIST Requirements;
  407. KSTATUS Status;
  408. RESOURCE_REQUIREMENT VectorRequirement;
  409. ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
  410. (Irp->MinorCode == IrpMinorQueryResources));
  411. //
  412. // Initialize a nice interrupt vector requirement in preparation.
  413. //
  414. RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
  415. VectorRequirement.Type = ResourceTypeInterruptVector;
  416. VectorRequirement.Minimum = 0;
  417. VectorRequirement.Maximum = -1;
  418. VectorRequirement.Length = 1;
  419. //
  420. // Loop through all configuration lists, creating a vector for each line.
  421. //
  422. Requirements = Irp->U.QueryResources.ResourceRequirements;
  423. Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
  424. &VectorRequirement);
  425. if (!KSUCCESS(Status)) {
  426. goto ProcessResourceRequirementsEnd;
  427. }
  428. ProcessResourceRequirementsEnd:
  429. return Status;
  430. }
  431. KSTATUS
  432. Sm91c1pStartDevice (
  433. PIRP Irp,
  434. PSM91C1_DEVICE Device
  435. )
  436. /*++
  437. Routine Description:
  438. This routine starts the SMSC91C111 LAN device.
  439. Arguments:
  440. Irp - Supplies a pointer to the start IRP.
  441. Device - Supplies a pointer to the device information.
  442. Return Value:
  443. Status code.
  444. --*/
  445. {
  446. ULONG AlignmentOffset;
  447. PRESOURCE_ALLOCATION Allocation;
  448. PRESOURCE_ALLOCATION_LIST AllocationList;
  449. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  450. PRESOURCE_ALLOCATION ControllerBase;
  451. PHYSICAL_ADDRESS EndAddress;
  452. BOOL Initialized;
  453. PRESOURCE_ALLOCATION LineAllocation;
  454. ULONG PageSize;
  455. PHYSICAL_ADDRESS PhysicalAddress;
  456. ULONG Size;
  457. KSTATUS Status;
  458. ControllerBase = NULL;
  459. Initialized = FALSE;
  460. //
  461. // Loop through the allocated resources to get the controller base and the
  462. // interrupt.
  463. //
  464. AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
  465. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  466. while (Allocation != NULL) {
  467. //
  468. // If the resource is an interrupt vector, then it should have an
  469. // owning interrupt line allocation.
  470. //
  471. if (Allocation->Type == ResourceTypeInterruptVector) {
  472. //
  473. // Currently only one interrupt resource is expected.
  474. //
  475. ASSERT(Device->InterruptResourcesFound == FALSE);
  476. ASSERT(Allocation->OwningAllocation != NULL);
  477. //
  478. // Save the line and vector number.
  479. //
  480. LineAllocation = Allocation->OwningAllocation;
  481. Device->InterruptLine = LineAllocation->Allocation;
  482. Device->InterruptVector = Allocation->Allocation;
  483. Device->InterruptResourcesFound = TRUE;
  484. //
  485. // Look for the first physical address reservation, the registers.
  486. //
  487. } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
  488. if (ControllerBase == NULL) {
  489. ControllerBase = Allocation;
  490. }
  491. }
  492. //
  493. // Get the next allocation in the list.
  494. //
  495. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  496. }
  497. //
  498. // Fail to start if the controller base was not found.
  499. //
  500. if (ControllerBase == NULL) {
  501. Status = STATUS_INVALID_CONFIGURATION;
  502. goto StartDeviceEnd;
  503. }
  504. //
  505. // Map the controller.
  506. //
  507. if (Device->ControllerBase == NULL) {
  508. //
  509. // Page align the mapping request.
  510. //
  511. PageSize = MmPageSize();
  512. PhysicalAddress = ControllerBase->Allocation;
  513. EndAddress = PhysicalAddress + ControllerBase->Length;
  514. PhysicalAddress = ALIGN_RANGE_DOWN(PhysicalAddress, PageSize);
  515. AlignmentOffset = ControllerBase->Allocation - PhysicalAddress;
  516. EndAddress = ALIGN_RANGE_UP(EndAddress, PageSize);
  517. Size = (ULONG)(EndAddress - PhysicalAddress);
  518. Device->ControllerBase = MmMapPhysicalAddress(PhysicalAddress,
  519. Size,
  520. TRUE,
  521. FALSE,
  522. TRUE);
  523. if (Device->ControllerBase == NULL) {
  524. Status = STATUS_NO_MEMORY;
  525. goto StartDeviceEnd;
  526. }
  527. Device->ControllerBase += AlignmentOffset;
  528. }
  529. ASSERT(Device->ControllerBase != NULL);
  530. //
  531. // Allocate the controller structures.
  532. //
  533. Status = Sm91c1pInitializeDeviceStructures(Device);
  534. if (!KSUCCESS(Status)) {
  535. goto StartDeviceEnd;
  536. }
  537. //
  538. // Start up the controller.
  539. //
  540. Status = Sm91c1pInitialize(Device);
  541. if (!KSUCCESS(Status)) {
  542. goto StartDeviceEnd;
  543. }
  544. Initialized = TRUE;
  545. //
  546. // Attempt to connect the interrupt.
  547. //
  548. ASSERT(Device->InterruptHandle == INVALID_HANDLE);
  549. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  550. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  551. Connect.Device = Irp->Device;
  552. Connect.LineNumber = Device->InterruptLine;
  553. Connect.Vector = Device->InterruptVector;
  554. Connect.InterruptServiceRoutine = Sm91c1pInterruptService;
  555. Connect.LowLevelServiceRoutine = Sm91c1pInterruptServiceWorker;
  556. Connect.Context = Device;
  557. Connect.Interrupt = &(Device->InterruptHandle);
  558. Status = IoConnectInterrupt(&Connect);
  559. if (!KSUCCESS(Status)) {
  560. goto StartDeviceEnd;
  561. }
  562. StartDeviceEnd:
  563. if (!KSUCCESS(Status)) {
  564. if (Initialized != FALSE) {
  565. ASSERT(Device->NetworkLink != NULL);
  566. NetRemoveLink(Device->NetworkLink);
  567. Device->NetworkLink = NULL;
  568. }
  569. Sm91c1pDestroyDeviceStructures(Device);
  570. }
  571. return Status;
  572. }