123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- smsc95hw.c
- Abstract:
- This module implements device support for the SMSC95xx family of USB
- Ethernet Controllers.
- Author:
- Evan Green 7-Nov-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- #include <minoca/usb/usb.h>
- #include "smsc95.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the maximum number of bulk out transfers that are allowed to be
- // submitted to USB at one time.
- //
- #define SM95_MAX_BULK_OUT_TRANSFER_COUNT 64
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines an SM95xx bulk out transfer. These transfers are
- allocated on demand and recycled when complete.
- Members:
- ListEntry - Stores a pointer to the next and previous bulk out transfer
- on the devices free transfer list.
- Device - Stores a pointer to the SM95 device that owns the transfer.
- UsbTransfer - Stores a pointer to the USB transfer that belongs to this
- SM95 transfer for the duration of its existence.
- Packet - Stores a pointer to the network packet buffer whose data is being
- sent by the USB transfer.
- --*/
- typedef struct _SM95_BULK_OUT_TRANSFER {
- LIST_ENTRY ListEntry;
- PSM95_DEVICE Device;
- PUSB_TRANSFER UsbTransfer;
- PNET_PACKET_BUFFER Packet;
- } SM95_BULK_OUT_TRANSFER, *PSM95_BULK_OUT_TRANSFER;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- Sm95pTransmitPacketCompletion (
- PUSB_TRANSFER Transfer
- );
- KSTATUS
- Sm95pEnableMac (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pSetupChecksumOffloading (
- PSM95_DEVICE Device,
- BOOL EnableTransmitChecksumOffload,
- BOOL EnableReceiveChecksumOffload
- );
- KSTATUS
- Sm95pSetMacAddress (
- PSM95_DEVICE Device,
- BYTE Address[ETHERNET_ADDRESS_SIZE]
- );
- KSTATUS
- Sm95pReadMacAddress (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pInitializePhy (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pRestartNway (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pReadEeprom (
- PSM95_DEVICE Device,
- ULONG Offset,
- ULONG Length,
- PBYTE Data
- );
- KSTATUS
- Sm95pWaitForEeprom (
- PSM95_DEVICE Device,
- BOOL ObserveEepromTimeout
- );
- KSTATUS
- Sm95pWriteMdio (
- PSM95_DEVICE Device,
- USHORT PhyId,
- USHORT Index,
- ULONG Data
- );
- KSTATUS
- Sm95pReadMdio (
- PSM95_DEVICE Device,
- USHORT PhyId,
- USHORT Index,
- PULONG Data
- );
- KSTATUS
- Sm95pWaitForPhy (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pWriteRegister (
- PSM95_DEVICE Device,
- USHORT Register,
- ULONG Data
- );
- KSTATUS
- Sm95pReadRegister (
- PSM95_DEVICE Device,
- USHORT Register,
- PULONG Data
- );
- KSTATUS
- Sm95pSubmitBulkInTransfers (
- PSM95_DEVICE Device
- );
- VOID
- Sm95pCancelBulkInTransfers (
- PSM95_DEVICE Device
- );
- PSM95_BULK_OUT_TRANSFER
- Sm95pAllocateBulkOutTransfer (
- PSM95_DEVICE Device
- );
- VOID
- Sm95pFreeBulkOutTransfer (
- PSM95_BULK_OUT_TRANSFER Transfer
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- BOOL Sm95DisablePacketDropping = FALSE;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- Sm95Send (
- PVOID DeviceContext,
- PNET_PACKET_LIST PacketList
- )
- /*++
- Routine Description:
- This routine sends data through the network.
- Arguments:
- DeviceContext - Supplies a pointer to the device context associated with
- the link down which this data is to be sent.
- PacketList - Supplies a pointer to a list of network packets to send. Data
- in these packets may be modified by this routine, but must not be used
- once this routine returns.
- Return Value:
- STATUS_SUCCESS if all packets were sent.
- STATUS_RESOURCE_IN_USE if some or all of the packets were dropped due to
- the hardware being backed up with too many packets to send.
- Other failure codes indicate that none of the packets were sent.
- --*/
- {
- ULONG DataSize;
- PSM95_DEVICE Device;
- PULONG Header;
- PNET_PACKET_BUFFER Packet;
- PSM95_BULK_OUT_TRANSFER Sm95Transfer;
- KSTATUS Status;
- PUSB_TRANSFER UsbTransfer;
- Device = (PSM95_DEVICE)DeviceContext;
- //
- // If there are more bulk out transfers in transit that allowed, drop all
- // of these packets.
- //
- if ((Device->BulkOutTransferCount >= SM95_MAX_BULK_OUT_TRANSFER_COUNT) &&
- (Sm95DisablePacketDropping == FALSE)) {
- return STATUS_RESOURCE_IN_USE;
- }
- //
- // Otherwise submit all the packets. This may stretch over the maximum
- // number of bulk out transfers, but it's a flexible line.
- //
- while (NET_PACKET_LIST_EMPTY(PacketList) == FALSE) {
- Packet = LIST_VALUE(PacketList->Head.Next,
- NET_PACKET_BUFFER,
- ListEntry);
- NET_REMOVE_PACKET_FROM_LIST(Packet, PacketList);
- ASSERT(IS_ALIGNED(Packet->BufferSize, MmGetIoBufferAlignment()) !=
- FALSE);
- ASSERT(IS_ALIGNED((UINTN)Packet->Buffer,
- MmGetIoBufferAlignment()) != FALSE);
- ASSERT(IS_ALIGNED((UINTN)Packet->BufferPhysicalAddress,
- MmGetIoBufferAlignment()) != FALSE);
- //
- // There might be legitimate reasons for this assert to be spurious,
- // but most likely this assert fired because something in the
- // networking stack failed to properly allocate the required header
- // space. Go figure out who allocated this packet.
- //
- ASSERT(Packet->DataOffset == SM95_TRANSMIT_HEADER_SIZE);
- DataSize = Packet->FooterOffset - Packet->DataOffset;
- Packet->DataOffset -= SM95_TRANSMIT_HEADER_SIZE;
- Header = Packet->Buffer;
- *Header = DataSize |
- SM95_TRANSMIT_FLAG_FIRST_SEGMENT |
- SM95_TRANSMIT_FLAG_LAST_SEGMENT;
- *(Header + 1) = DataSize;
- //
- // Allocate a transfer for this packet. All packets need to be dealt
- // with, so if the allocation or submission fails then free the buffer.
- //
- Sm95Transfer = Sm95pAllocateBulkOutTransfer(Device);
- if (Sm95Transfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- RtlDebugPrint("SM95: Failed to allocate transfer.\n");
- NetFreeBuffer(Packet);
- break;
- }
- Sm95Transfer->Packet = Packet;
- UsbTransfer = Sm95Transfer->UsbTransfer;
- UsbTransfer->Length = Packet->FooterOffset;
- UsbTransfer->BufferActualLength = Packet->BufferSize;
- UsbTransfer->Buffer = Header;
- UsbTransfer->BufferPhysicalAddress = Packet->BufferPhysicalAddress;
- RtlAtomicAdd32(&(Device->BulkOutTransferCount), 1);
- Status = UsbSubmitTransfer(UsbTransfer);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("SM95: Failed to submit transmit packet: %d\n",
- Status);
- Sm95Transfer->Packet = NULL;
- Sm95pFreeBulkOutTransfer(Sm95Transfer);
- NetFreeBuffer(Packet);
- RtlAtomicAdd32(&(Device->BulkOutTransferCount), -1);
- break;
- }
- }
- return Status;
- }
- KSTATUS
- Sm95GetSetInformation (
- PVOID DeviceContext,
- NET_LINK_INFORMATION_TYPE InformationType,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets the network device layer's link information.
- Arguments:
- DeviceContext - Supplies a pointer to the device context associated with
- the link for which information is being set or queried.
- InformationType - Supplies the type of information being queried or set.
- Data - Supplies a pointer to the data buffer where the data is either
- returned for a get operation or given for a set operation.
- DataSize - Supplies a pointer that on input contains the size of the data
- buffer. On output, contains the required size of the data buffer.
- Set - Supplies a boolean indicating if this is a get operation (FALSE) or a
- set operation (TRUE).
- Return Value:
- Status code.
- --*/
- {
- PULONG Flags;
- KSTATUS Status;
- switch (InformationType) {
- case NetLinkInformationChecksumOffload:
- if (*DataSize != sizeof(ULONG)) {
- return STATUS_INVALID_PARAMETER;
- }
- if (Set != FALSE) {
- return STATUS_NOT_SUPPORTED;
- }
- Flags = (PULONG)Data;
- *Flags = 0;
- break;
- default:
- Status = STATUS_NOT_SUPPORTED;
- break;
- }
- return Status;
- }
- VOID
- Sm95InterruptTransferCompletion (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine is called when the interrupt transfer returns. It processes
- the notification from the device.
- Arguments:
- Transfer - Supplies a pointer to the transfer that completed.
- Return Value:
- None.
- --*/
- {
- PSM95_DEVICE Device;
- BOOL OriginalLinkUp;
- ULONG Source;
- KSTATUS Status;
- ULONG Value;
- Device = Transfer->UserData;
- ASSERT(Transfer == Device->InterruptTransfer);
- //
- // If the transfer failed, don't bother with the data. If it was cancelled,
- // just exit immediately. The device was likely removed.
- //
- if (!KSUCCESS(Transfer->Status)) {
- if (Transfer->Status == STATUS_OPERATION_CANCELLED) {
- return;
- }
- goto InterruptTransferCompletionEnd;
- }
- if (Transfer->LengthTransferred != sizeof(ULONG)) {
- RtlDebugPrint("SM95: Got weird interrupt transfer of size %d.\n",
- Transfer->LengthTransferred);
- goto InterruptTransferCompletionEnd;
- }
- RtlCopyMemory(&Value, Transfer->Buffer, sizeof(ULONG));
- if ((Value & SM95_INTERRUPT_STATUS_PHY) != 0) {
- //
- // Read the interrupt status to clear it from the PHY.
- //
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- Sm95PhyRegisterInterruptSource,
- &Source);
- if (!KSUCCESS(Status)) {
- goto InterruptTransferCompletionEnd;
- }
- //
- // Read the status register to find out what happened to the link. Read
- // the register twice as the link status bit is sticky.
- //
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicStatus,
- &Value);
- if (!KSUCCESS(Status)) {
- goto InterruptTransferCompletionEnd;
- }
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicStatus,
- &Value);
- if (!KSUCCESS(Status)) {
- goto InterruptTransferCompletionEnd;
- }
- if ((Value & MII_BASIC_STATUS_LINK_STATUS) != 0) {
- if ((Value & MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) != 0) {
- //
- // Get the current link state.
- //
- NetGetLinkState(Device->NetworkLink, &OriginalLinkUp, NULL);
- //
- // TODO: Get the real device speed when generic MII support is
- // added.
- //
- NetSetLinkState(Device->NetworkLink, TRUE, NET_SPEED_100_MBPS);
- //
- // Submit the bulk IN transfer if the original state was down.
- //
- if (OriginalLinkUp == FALSE) {
- Status = Sm95pSubmitBulkInTransfers(Device);
- if (!KSUCCESS(Status)) {
- goto InterruptTransferCompletionEnd;
- }
- }
- }
- } else {
- NetSetLinkState(Device->NetworkLink, FALSE, 0);
- //
- // Try to cancel the bulk IN transfer. If the transfer has also
- // completed, it may be waiting to run, in which case it is too
- // late to cancel. That's OK as it will check the link state and
- // see that it should not re-submit. Make sure that the cancel
- // routine does not wait for the transfer to reach the inactive
- // state as the transfer could be sitting on the completed transfer
- // queue behind this transfer.
- //
- Sm95pCancelBulkInTransfers(Device);
- }
- }
- //
- // Write the interrupt status register to clear the interrupts.
- //
- Status = Sm95pWriteRegister(Device,
- Sm95RegisterInterruptStatus,
- SM95_INTERRUPT_MASK);
- if (!KSUCCESS(Status)) {
- goto InterruptTransferCompletionEnd;
- }
- InterruptTransferCompletionEnd:
- //
- // Resubmit the transfer.
- //
- Status = UsbSubmitTransfer(Transfer);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("SM95: Failed to resubmit interrupt transfer: %d.\n",
- Status);
- }
- return;
- }
- VOID
- Sm95BulkInTransferCompletion (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine is called when the bulk in transfer returns. It processes
- the notification from the device.
- Arguments:
- Transfer - Supplies a pointer to the transfer that completed.
- Return Value:
- None.
- --*/
- {
- PUCHAR Data;
- PSM95_DEVICE Device;
- PULONG Header;
- ULONG Length;
- BOOL LinkUp;
- NET_PACKET_BUFFER Packet;
- ULONG PacketLength;
- PHYSICAL_ADDRESS PhysicalAddress;
- KSTATUS Status;
- Device = Transfer->UserData;
- Status = STATUS_SUCCESS;
- //
- // If the transfer failed, don't bother with the data.
- //
- if (!KSUCCESS(Transfer->Status)) {
- //
- // If the transfer stalled, attempt to clear the HALT feature from the
- // endpoint.
- //
- if (Transfer->Error == UsbErrorTransferStalled) {
- Status = UsbClearFeature(Device->UsbCoreHandle,
- USB_SETUP_REQUEST_ENDPOINT_RECIPIENT,
- USB_FEATURE_ENDPOINT_HALT,
- Device->BulkInEndpoint);
- }
- goto BulkInTransferCompletionEnd;
- }
- Data = Transfer->Buffer;
- PhysicalAddress = Transfer->BufferPhysicalAddress;
- Length = Transfer->LengthTransferred;
- Packet.IoBuffer = NULL;
- Packet.Flags = 0;
- while (Length > 0) {
- if (Length < sizeof(ULONG)) {
- RtlDebugPrint("SM95: Received odd sized data (%d).\n", Length);
- break;
- }
- Header = (PULONG)Data;
- ASSERT(((UINTN)Header & 0x3) == 0);
- if ((*Header & SM95_RECEIVE_FLAG_ERROR_SUMMARY) != 0) {
- RtlDebugPrint("SM95: Receive error summary 0x%x\n", *Header);
- break;
- }
- PacketLength = (*Header & SM95_RECEIVE_FRAME_LENGTH_MASK) >>
- SM95_RECEIVE_FRAME_LENGTH_SHIFT;
- if (PacketLength > Length - sizeof(ULONG)) {
- RtlDebugPrint("SM95: Got packet purported to be size %d, but "
- "only %d bytes remaining in the transfer.\n",
- PacketLength,
- Length - sizeof(ULONG));
- break;
- }
- Packet.Buffer = Data + sizeof(ULONG) + SM95_RECEIVE_DATA_OFFSET;
- Packet.BufferPhysicalAddress = PhysicalAddress +
- sizeof(ULONG) +
- SM95_RECEIVE_DATA_OFFSET;
- Packet.BufferSize = PacketLength - sizeof(ULONG);
- Packet.DataSize = Packet.BufferSize;
- Packet.DataOffset = 0;
- Packet.FooterOffset = Packet.DataSize;
- NetProcessReceivedPacket(Device->NetworkLink, &Packet);
- //
- // Advance to the next packet, adding an extra 4 and aligning the total
- // offset to 4.
- //
- PacketLength += sizeof(ULONG) + SM95_RECEIVE_DATA_OFFSET;
- PacketLength = ALIGN_RANGE_UP(PacketLength, sizeof(ULONG));
- if (PacketLength >= Length) {
- break;
- }
- Length -= PacketLength;
- Data += PacketLength;
- PhysicalAddress += PacketLength;
- }
- BulkInTransferCompletionEnd:
- //
- // If the link is still up and everything went smashingly above, resubmit
- // the transfer and around it goes.
- //
- NetGetLinkState(Device->NetworkLink, &LinkUp, NULL);
- if (KSUCCESS(Status) && (LinkUp != FALSE)) {
- Status = UsbSubmitTransfer(Transfer);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("SM95: Failed to resubmit bulk IN transfer.\n");
- }
- }
- return;
- }
- KSTATUS
- Sm95pInitialize (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine initializes and enables the SMSC95xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG CurrentTime;
- ULONG ReadValue;
- USB_DEVICE_SPEED Speed;
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONGLONG TimeoutTicks;
- ULONG Value;
- TimeoutTicks = HlQueryTimeCounterFrequency() * SM95_DEVICE_TIMEOUT;
- //
- // The device's PHY is at a fixed address.
- //
- Device->PhyId = SM95_PHY_ID;
- //
- // Perform a reset of the device.
- //
- Value = SM95_HARDWARE_CONFIG_LITE_RESET;
- Status = Sm95pWriteRegister(Device, Sm95RegisterHardwareConfig, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- Status = Sm95pReadRegister(Device,
- Sm95RegisterHardwareConfig,
- &ReadValue);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- if ((ReadValue & SM95_HARDWARE_CONFIG_LITE_RESET) == 0) {
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- Status = STATUS_TIMEOUT;
- goto InitializeEnd;
- }
- //
- // Also reset the PHY.
- //
- Value = SM95_POWER_CONTROL_PHY_RESET;
- Status = Sm95pWriteRegister(Device, Sm95RegisterPowerControl, Value);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- Status = Sm95pReadRegister(Device,
- Sm95RegisterPowerControl,
- &ReadValue);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- if ((ReadValue & SM95_POWER_CONTROL_PHY_RESET) == 0) {
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- Status = STATUS_TIMEOUT;
- goto InitializeEnd;
- }
- //
- // Read the MAC address from the EEPROM and program it into the device.
- // If there was no EEPROM, generate a random MAC address.
- //
- Status = Sm95pReadMacAddress(Device);
- if (Status == STATUS_INVALID_ADDRESS) {
- NetCreateEthernetAddress(Device->MacAddress);
- } else if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Status = Sm95pSetMacAddress(Device, Device->MacAddress);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Enable BIR.
- //
- Status = Sm95pReadRegister(Device, Sm95RegisterHardwareConfig, &ReadValue);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Value = ReadValue | SM95_HARDWARE_CONFIG_BULK_IN_EMPTY_RESPONSE;
- Status = Sm95pWriteRegister(Device, Sm95RegisterHardwareConfig, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Set up the burst capability.
- //
- Status = UsbGetDeviceSpeed(Device->UsbCoreHandle, &Speed);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- if (Speed == UsbDeviceSpeedHigh) {
- Value = SM95_HIGH_SPEED_BURST_SIZE / SM95_HIGH_SPEED_TRANSFER_SIZE;
- } else {
- ASSERT(Speed == UsbDeviceSpeedFull);
- Value = SM95_FULL_SPEED_BURST_SIZE / SM95_FULL_SPEED_TRANSFER_SIZE;
- }
- Status = Sm95pWriteRegister(Device, Sm95RegisterBurstCapability, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Set the bulk IN delay.
- //
- Value = SM95_DEFAULT_BULK_IN_DELAY;
- Status = Sm95pWriteRegister(Device, Sm95RegisterBulkInDelay, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Enable MEF and BCE.
- //
- Status = Sm95pReadRegister(Device, Sm95RegisterHardwareConfig, &Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Value |= SM95_HARDWARE_CONFIG_MULTIPLE_ETHERNET_FRAMES |
- SM95_HARDWARE_CONFIG_BURST_CAP_ENABLED;
- Value &= ~SM95_HARDWARE_CONFIG_RX_DATA_OFFSET_MASK;
- Value |= SM95_RECEIVE_DATA_OFFSET <<
- SM95_HARDWARE_CONFIG_RX_DATA_OFFSET_SHIFT;
- Status = Sm95pWriteRegister(Device, Sm95RegisterHardwareConfig, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Clear all interrupts.
- //
- Value = SM95_INTERRUPT_MASK;
- Status = Sm95pWriteRegister(Device, Sm95RegisterInterruptStatus, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Configure the GPIO pins as LED outputs.
- //
- Value = SM95_LED_GPIO_CONFIG_SPEED_LED | SM95_LED_GPIO_CONFIG_LINK_LED |
- SM95_LED_GPIO_CONFIG_FULL_DUPLEX_LED;
- Status = Sm95pWriteRegister(Device, Sm95RegisterLedGpioConfig, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Initialize transmit parameters.
- //
- Status = Sm95pWriteRegister(Device, Sm95RegisterFlowControl, 0);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Value = SM95_AUTO_FLOW_CONTROL_DEFAULT;
- Status = Sm95pWriteRegister(Device, Sm95RegisterAutoFlowControl, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Status = Sm95pReadRegister(Device,
- Sm95RegisterMacControl,
- &(Device->MacControl));
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Initialize receive parameters.
- //
- Value = SM95_VLAN_8021Q;
- Status = Sm95pWriteRegister(Device, Sm95RegisterVlan1, Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Disable checksum offload engines.
- //
- Status = Sm95pSetupChecksumOffloading(Device, FALSE, FALSE);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Status = Sm95pInitializePhy(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Enable PHY interrupts.
- //
- Status = Sm95pReadRegister(Device,
- Sm95RegisterInterruptEndpointControl,
- &Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Value |= SM95_INTERRUPT_ENDPOINT_CONTROL_PHY_INTERRUPTS;
- Status = Sm95pWriteRegister(Device,
- Sm95RegisterInterruptEndpointControl,
- Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Status = Sm95pEnableMac(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Do an initial read of the MII status and report the link as up if it
- // started connected. Read the register twice as the link status bit is
- // sticky.
- //
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicStatus,
- &Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicStatus,
- &Value);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Notify the networking core of this new link now that the device is ready
- // to send and receive data, pending media being present.
- //
- Status = Sm95pAddNetworkDevice(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- if (((Value & MII_BASIC_STATUS_LINK_STATUS) != 0) &&
- ((Value & MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) != 0)) {
- //
- // TODO: Get the real device speed when generic MII support is added.
- //
- NetSetLinkState(Device->NetworkLink, TRUE, NET_SPEED_100_MBPS);
- //
- // Submit the bulk IN transfer.
- //
- Status = Sm95pSubmitBulkInTransfers(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- }
- //
- // Submit the interrupt transfer.
- //
- Status = UsbSubmitTransfer(Device->InterruptTransfer);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- InitializeEnd:
- return Status;
- }
- VOID
- Sm95pDestroyBulkOutTransfers (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine destroys the SMSC95xx device's bulk out tranfers.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- PSM95_BULK_OUT_TRANSFER Sm95Transfer;
- while (LIST_EMPTY(&(Device->BulkOutFreeTransferList)) == FALSE) {
- Sm95Transfer = LIST_VALUE(Device->BulkOutFreeTransferList.Next,
- SM95_BULK_OUT_TRANSFER,
- ListEntry);
- ASSERT(Sm95Transfer->Packet == NULL);
- LIST_REMOVE(&(Sm95Transfer->ListEntry));
- UsbDestroyTransfer(Sm95Transfer->UsbTransfer);
- MmFreePagedPool(Sm95Transfer);
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- Sm95pTransmitPacketCompletion (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine is called when an asynchronous I/O request completes with
- success, failure, or is cancelled.
- Arguments:
- Transfer - Supplies a pointer to the transfer that completed.
- Return Value:
- None.
- --*/
- {
- PSM95_BULK_OUT_TRANSFER Sm95Transfer;
- Sm95Transfer = Transfer->UserData;
- RtlAtomicAdd32(&(Sm95Transfer->Device->BulkOutTransferCount), -1);
- NetFreeBuffer(Sm95Transfer->Packet);
- Sm95Transfer->Packet = NULL;
- Sm95pFreeBulkOutTransfer(Sm95Transfer);
- return;
- }
- KSTATUS
- Sm95pEnableMac (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine enables transmitting and receiving of data from the wild.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- //
- // Disable multicast for now.
- //
- Device->MacControl &= ~(SM95_MAC_CONTROL_PRMS |
- SM95_MAC_CONTROL_MULTICAST_PAS |
- SM95_MAC_CONTROL_HP_FILTER |
- SM95_MAC_CONTROL_RECEIVE_OWN);
- //
- // Enable transmit and receive at the MAC.
- //
- Device->MacControl |= SM95_MAC_CONTROL_FULL_DUPLEX|
- SM95_MAC_CONTROL_ENABLE_TRANSMIT |
- SM95_MAC_CONTROL_ENABLE_RECEIVE;
- Status = Sm95pWriteRegister(Device,
- Sm95RegisterMacControl,
- Device->MacControl);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Enable transmit at the SCSRs.
- //
- Status = Sm95pWriteRegister(Device,
- Sm95RegisterTransmitControl,
- SM95_TRANSMIT_CONTROL_ENABLE);
- return Status;
- }
- KSTATUS
- Sm95pSetupChecksumOffloading (
- PSM95_DEVICE Device,
- BOOL EnableTransmitChecksumOffload,
- BOOL EnableReceiveChecksumOffload
- )
- /*++
- Routine Description:
- This routine enables or disables the checksum offload engines for transmit
- and receive packets.
- Arguments:
- Device - Supplies a pointer to the device.
- EnableTransmitChecksumOffload - Supplies a boolean indicating whether or
- not checksum offloading should be enabled for outgoing packets.
- EnableReceiveChecksumOffload - Supplies a boolean indicating whether or not
- checksum offloading should be enabled for incoming packets.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- ULONG Value;
- Status = Sm95pReadRegister(Device,
- Sm95RegisterChecksumOffloadControl,
- &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Value &= ~(SM95_CHECKSUM_CONTROL_TRANSMIT_ENABLE |
- SM95_CHECKSUM_CONTROL_RECEIVE_ENABLE);
- if (EnableTransmitChecksumOffload != FALSE) {
- Value |= SM95_CHECKSUM_CONTROL_TRANSMIT_ENABLE;
- }
- if (EnableReceiveChecksumOffload != FALSE) {
- Value |= SM95_CHECKSUM_CONTROL_RECEIVE_ENABLE;
- }
- Status = Sm95pWriteRegister(Device,
- Sm95RegisterChecksumOffloadControl,
- Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- return Status;
- }
- KSTATUS
- Sm95pSetMacAddress (
- PSM95_DEVICE Device,
- BYTE Address[ETHERNET_ADDRESS_SIZE]
- )
- /*++
- Routine Description:
- This routine sets the individual physical address for the given device.
- Arguments:
- Device - Supplies a pointer to the device.
- Address - Supplies the new address to set.
- Return Value:
- Status code.
- --*/
- {
- ULONG AddressHigh;
- ULONG AddressLow;
- KSTATUS Status;
- RtlCopyMemory(&AddressLow, Address, sizeof(ULONG));
- AddressHigh = 0;
- RtlCopyMemory(&AddressHigh, &(Address[sizeof(ULONG)]), sizeof(USHORT));
- Status = Sm95pWriteRegister(Device, Sm95RegisterMacAddressLow, AddressLow);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Status = Sm95pWriteRegister(Device,
- Sm95RegisterMacAddressHigh,
- AddressHigh);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- Sm95pReadMacAddress (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reads the MAC address out of the EEPROM on the SMSC95xx. The
- MAC address will be stored in the device structure.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- Status = Sm95pReadEeprom(Device,
- SM95_EEPROM_MAC_ADDRESS,
- sizeof(Device->MacAddress),
- Device->MacAddress);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- if (NetIsEthernetAddressValid(Device->MacAddress) == FALSE) {
- return STATUS_INVALID_ADDRESS;
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- Sm95pInitializePhy (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine initializes the PHY on the SMSC95xx.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- ULONG Value;
- Status = Sm95pWriteMdio(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- MII_BASIC_CONTROL_RESET);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Wait for the reset to complete.
- //
- do {
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- } while ((Value & MII_BASIC_CONTROL_RESET) != 0);
- //
- // Advertise all modes and pause capabilities.
- //
- Value = MII_ADVERTISE_ALL | MII_ADVERTISE_CSMA | MII_ADVERTISE_PAUSE |
- MII_ADVERTISE_PAUSE_ASYMMETRIC;
- Status = Sm95pWriteMdio(Device, Device->PhyId, MiiRegisterAdvertise, Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Read the interrupt status register to clear the bits.
- //
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- Sm95PhyRegisterInterruptSource,
- &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Write the interrupt mask.
- //
- Value = SM95_PHY_INTERRUPT_AUTONEGOTIATION_COMPLETE |
- SM95_PHY_INTERRUPT_LINK_DOWN;
- Status = Sm95pWriteMdio(Device,
- Device->PhyId,
- Sm95PhyRegisterInterruptMask,
- Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Restart auto-negotiation.
- //
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Value |= MII_BASIC_CONTROL_RESTART_AUTONEGOTIATION;
- Status = Sm95pWriteMdio(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- return Status;
- }
- KSTATUS
- Sm95pRestartNway (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine restarts N-Way (autonegotiation) for the device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- ULONG Value;
- //
- // Read the control register, and restart autonegotiation if it's enabled.
- //
- Status = Sm95pReadMdio(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- if ((Value & MII_BASIC_CONTROL_ENABLE_AUTONEGOTIATION) != 0) {
- Value |= MII_BASIC_CONTROL_RESTART_AUTONEGOTIATION;
- Status = Sm95pWriteMdio(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- Value);
- } else {
- Status = STATUS_INVALID_CONFIGURATION;
- }
- return Status;
- }
- KSTATUS
- Sm95pReadEeprom (
- PSM95_DEVICE Device,
- ULONG Offset,
- ULONG Length,
- PBYTE Data
- )
- /*++
- Routine Description:
- This routine reads from the EEPROM on the SMSC95xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Offset - Supplies the offset in bytes from the beginning of the EEPROM to
- read from.
- Length - Supplies the number of bytes to read.
- Data - Supplies a pointer where the EEPROM data will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- ULONG ByteIndex;
- ULONG Command;
- KSTATUS Status;
- ULONG Value;
- Status = Sm95pWaitForEeprom(Device, FALSE);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Read bytes from the EEPROM one at a time.
- //
- for (ByteIndex = 0; ByteIndex < Length; ByteIndex += 1) {
- //
- // Set up the command register to read the EEPROM at the specified
- // offset.
- //
- ASSERT(Offset + ByteIndex <= SM95_EEPROM_COMMAND_ADDRESS_MASK);
- Command = SM95_EEPROM_COMMAND_BUSY |
- ((Offset + ByteIndex) & SM95_EEPROM_COMMAND_ADDRESS_MASK);
- Status = Sm95pWriteRegister(Device, Sm95RegisterEepromCommand, Command);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Wait for the EEPROM to accept the command.
- //
- Status = Sm95pWaitForEeprom(Device, TRUE);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Read the spoils out of the data register.
- //
- Status = Sm95pReadRegister(Device, Sm95RegisterEepromData, &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Data[ByteIndex] = (BYTE)Value;
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- Sm95pWaitForEeprom (
- PSM95_DEVICE Device,
- BOOL ObserveEepromTimeout
- )
- /*++
- Routine Description:
- This routine waits for the EEPROM to finish or time out.
- Arguments:
- Device - Supplies a pointer to the device.
- ObserveEepromTimeout - Supplies a boolean indicating if the EEPROM timeout
- bit should be checked as well as the busy bit (TRUE) or if only the
- busy bit should be waited on (FALSE).
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONG Value;
- Timeout = KeGetRecentTimeCounter() +
- (HlQueryTimeCounterFrequency() * SM95_EEPROM_TIMEOUT);
- do {
- Status = Sm95pReadRegister(Device, Sm95RegisterEepromCommand, &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- if ((ObserveEepromTimeout != FALSE) &&
- ((Value & SM95_EEPROM_COMMAND_TIMEOUT) != 0)) {
- break;
- }
- if ((Value & SM95_EEPROM_COMMAND_BUSY) == 0) {
- return STATUS_SUCCESS;
- }
- } while (KeGetRecentTimeCounter() <= Timeout);
- return STATUS_TIMEOUT;
- }
- KSTATUS
- Sm95pWriteMdio (
- PSM95_DEVICE Device,
- USHORT PhyId,
- USHORT Index,
- ULONG Data
- )
- /*++
- Routine Description:
- This routine performs an MDIO register write.
- Arguments:
- Device - Supplies a pointer to the device.
- PhyId - Supplies the device ID to write to.
- Index - Supplies the register to write.
- Data - Supplies the value to write.
- Return Value:
- Status code.
- --*/
- {
- ULONG Address;
- KSTATUS Status;
- Status = Sm95pWaitForPhy(Device);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Write the data contents first.
- //
- Status = Sm95pWriteRegister(Device, Sm95RegisterMiiData, Data);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Write the address into the address register to execute the write.
- //
- Address = (PhyId << SM95_MII_ADDRESS_PHY_ID_SHIFT) |
- (Index << SM95_MII_ADDRESS_INDEX_SHIFT) |
- SM95_MII_ADDRESS_WRITE;
- Status = Sm95pWriteRegister(Device, Sm95RegisterMiiAddress, Address);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- return Status;
- }
- KSTATUS
- Sm95pReadMdio (
- PSM95_DEVICE Device,
- USHORT PhyId,
- USHORT Index,
- PULONG Data
- )
- /*++
- Routine Description:
- This routine performs an MDIO register read.
- Arguments:
- Device - Supplies a pointer to the device.
- PhyId - Supplies the device ID to read from.
- Index - Supplies the register to read.
- Data - Supplies a pointer where the register contents will be returned on
- success.
- Return Value:
- Status code.
- --*/
- {
- ULONG Address;
- KSTATUS Status;
- ULONG Value;
- Status = Sm95pWaitForPhy(Device);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Write the address into the address register.
- //
- Address = (PhyId << SM95_MII_ADDRESS_PHY_ID_SHIFT) |
- (Index << SM95_MII_ADDRESS_INDEX_SHIFT);
- Status = Sm95pWriteRegister(Device, Sm95RegisterMiiAddress, Address);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Status = Sm95pWaitForPhy(Device);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Read the requested data out of the data register.
- //
- Status = Sm95pReadRegister(Device, Sm95RegisterMiiData, &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- *Data = Value & 0x0000FFFF;
- return Status;
- }
- KSTATUS
- Sm95pWaitForPhy (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine waits until the PHY is not busy.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONG Value;
- Timeout = KeGetRecentTimeCounter() +
- (HlQueryTimeCounterFrequency() * SM95_DEVICE_TIMEOUT);
- do {
- Status = Sm95pReadRegister(Device, Sm95RegisterMiiAddress, &Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- if ((Value & SM95_MII_ADDRESS_BUSY) == 0) {
- return STATUS_SUCCESS;
- }
- } while (KeGetRecentTimeCounter() <= Timeout);
- return STATUS_TIMEOUT;
- }
- KSTATUS
- Sm95pWriteRegister (
- PSM95_DEVICE Device,
- USHORT Register,
- ULONG Data
- )
- /*++
- Routine Description:
- This routine performs a register write to the SMSC95xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Register - Supplies the register number to write to.
- Data - Supplies the value to write.
- Return Value:
- Status code.
- --*/
- {
- PUSB_TRANSFER ControlTransfer;
- PUSB_SETUP_PACKET Setup;
- KSTATUS Status;
- ControlTransfer = Device->ControlTransfer;
- Setup = ControlTransfer->Buffer;
- Setup->RequestType = USB_SETUP_REQUEST_TO_DEVICE |
- USB_SETUP_REQUEST_VENDOR |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- Setup->Request = SM95_VENDOR_REQUEST_WRITE_REGISTER;
- Setup->Value = 0;
- Setup->Index = Register;
- Setup->Length = sizeof(ULONG);
- RtlCopyMemory(Setup + 1, &Data, sizeof(ULONG));
- ControlTransfer->Direction = UsbTransferDirectionOut;
- ControlTransfer->Length = sizeof(USB_SETUP_PACKET) + sizeof(ULONG);
- Status = UsbSubmitSynchronousTransfer(ControlTransfer);
- return Status;
- }
- KSTATUS
- Sm95pReadRegister (
- PSM95_DEVICE Device,
- USHORT Register,
- PULONG Data
- )
- /*++
- Routine Description:
- This routine performs a register read from the SMSC95xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Register - Supplies the register number to read from.
- Data - Supplies a pointer where the register contents will be returned on
- success.
- Return Value:
- Status code.
- --*/
- {
- PUSB_TRANSFER ControlTransfer;
- PUSB_SETUP_PACKET Setup;
- KSTATUS Status;
- ControlTransfer = Device->ControlTransfer;
- Setup = ControlTransfer->Buffer;
- Setup->RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_VENDOR |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- Setup->Request = SM95_VENDOR_REQUEST_READ_REGISTER;
- Setup->Value = 0;
- Setup->Index = Register;
- Setup->Length = sizeof(ULONG);
- ControlTransfer->Direction = UsbTransferDirectionIn;
- ControlTransfer->Length = sizeof(USB_SETUP_PACKET) + sizeof(ULONG);
- Status = UsbSubmitSynchronousTransfer(ControlTransfer);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- RtlCopyMemory(Data, Setup + 1, sizeof(ULONG));
- return Status;
- }
- KSTATUS
- Sm95pSubmitBulkInTransfers (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine submits all the bulk IN transfers allocated for the device.
- Arguments:
- Device - Supplies a pointer to an SM95 device.
- Return Value:
- Status code.
- --*/
- {
- ULONG Index;
- KSTATUS Status;
- for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
- Status = UsbSubmitTransfer(Device->BulkInTransfer[Index]);
- if (!KSUCCESS(Status)) {
- break;
- }
- }
- return Status;
- }
- VOID
- Sm95pCancelBulkInTransfers (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine attempts to cancel all the bulk IN transfers for the device.
- Arguments:
- Device - Supplies a pointer to an SM95 device.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
- UsbCancelTransfer(Device->BulkInTransfer[Index], FALSE);
- }
- return;
- }
- PSM95_BULK_OUT_TRANSFER
- Sm95pAllocateBulkOutTransfer (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine allocates an SM95 bulk OUT transfer. If there are no free bulk
- OUT transfers ready to go, it will create a new transfer.
- Arguments:
- Device - Supplies a pointer to the SM95 device in need of a new transfer.
- Return Value:
- Returns a pointer to the allocated SM95 bulk OUT transfer on success or
- NULL on failure.
- --*/
- {
- PSM95_BULK_OUT_TRANSFER Sm95Transfer;
- PUSB_TRANSFER UsbTransfer;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Loop attempting to use the most recently released existing transfer, but
- // allocate a new transfer if none are available.
- //
- Sm95Transfer = NULL;
- while (Sm95Transfer == NULL) {
- if (LIST_EMPTY(&(Device->BulkOutFreeTransferList)) != FALSE) {
- Sm95Transfer = MmAllocatePagedPool(sizeof(SM95_BULK_OUT_TRANSFER),
- SM95_ALLOCATION_TAG);
- if (Sm95Transfer == NULL) {
- goto AllocateBulkOutTransferEnd;
- }
- UsbTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- Device->BulkOutEndpoint,
- SM95_MAX_PACKET_SIZE,
- 0);
- if (UsbTransfer == NULL) {
- MmFreePagedPool(Sm95Transfer);
- Sm95Transfer = NULL;
- goto AllocateBulkOutTransferEnd;
- }
- UsbTransfer->Direction = UsbTransferDirectionOut;
- UsbTransfer->CallbackRoutine = Sm95pTransmitPacketCompletion;
- UsbTransfer->UserData = Sm95Transfer;
- Sm95Transfer->Device = Device;
- Sm95Transfer->UsbTransfer = UsbTransfer;
- Sm95Transfer->Packet = NULL;
- } else {
- KeAcquireQueuedLock(Device->BulkOutListLock);
- if (LIST_EMPTY(&(Device->BulkOutFreeTransferList)) == FALSE) {
- Sm95Transfer = LIST_VALUE(Device->BulkOutFreeTransferList.Next,
- SM95_BULK_OUT_TRANSFER,
- ListEntry);
- LIST_REMOVE(&(Sm95Transfer->ListEntry));
- }
- KeReleaseQueuedLock(Device->BulkOutListLock);
- }
- }
- AllocateBulkOutTransferEnd:
- return Sm95Transfer;
- }
- VOID
- Sm95pFreeBulkOutTransfer (
- PSM95_BULK_OUT_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine releases an SM95 bulk OUT transfer for recycling.
- Arguments:
- Transfer - Supplies a pointer to the SM95 transfer to be recycled.
- Return Value:
- None.
- --*/
- {
- PSM95_DEVICE Device;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Insert it onto the head of the list so it stays hot.
- //
- Device = Transfer->Device;
- KeAcquireQueuedLock(Device->BulkOutListLock);
- INSERT_AFTER(&(Transfer->ListEntry), &(Device->BulkOutFreeTransferList));
- KeReleaseQueuedLock(Device->BulkOutListLock);
- return;
- }
|