1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- ftdi.c
- Abstract:
- This module implements the FTDI USB to Serial Port KD USB driver.
- Author:
- Evan Green 3-Apr-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include "kdusbp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define KD_FTDI_CONFIGURATION_BUFFER_SIZE 256
- #define FTDI_REQUEST_RESET 0x00
- #define FTDI_REQUEST_SET_BAUD_RATE 0x03
- #define FTDI_INTERFACE_ANY 0
- #define FTDI_INTERFACE_A 1
- #define FTDI_INTERFACE_B 2
- #define FTDI_INTERFACE_C 3
- #define FTDI_INTERFACE_D 4
- #define FTDI_REVISION_AM 0x200
- #define FTDI_REVISION_BM 0x400
- #define FTDI_REVISION_2232C 0x500
- #define FTDI_FUNDAMENTAL_CLOCK 24000000
- #define FTDI_MAX_DIVISOR_AM 0x1FFF8
- #define FTDI_MAX_DIVISOR_BM 0x1FFFF
- //
- // Define the number of status bytes that come in before every read.
- //
- #define FTDI_READ_STATUS_SIZE 2
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _FTDI_CHIP_TYPE {
- FtdiTypeInvalid,
- FtdiTypeOld,
- FtdiTypeAm,
- FtdiTypeBm,
- FtdiType2232C
- } FTDI_CHIP_TYPE, *PFTDI_CHIP_TYPE;
- /*++
- Structure Description:
- This structure describes the context of an FTDI USB device.
- Members:
- Device - Stores a pointer to the USB device.
- BulkOutEndpoint - Stores the bulk out endpoint information.
- BulkInEndpoint - Stores the bulk in endpoint information.
- TransferOut - Stores the outgoing transfer.
- TransferIn - Stores the incoming transfer.
- TransferInOffset - Stores the current offset to the IN transfer data where
- the next byte to be returned is.
- TransferInQueued - Stores a boolean indicating whether or not the
- receive transfer has been submitted.
- TransferInSetup - Stores a boolean indicating whether or not the receive
- transfer has been set up (and therefore needs retiring).
- Index - Stores the serial port to talk to. See FTDI_INTERFACE_* definitions.
- ChipType - Stores the chip type.
- --*/
- typedef struct _KD_FTDI_DEVICE {
- PKD_USB_DEVICE Device;
- DEBUG_USB_ENDPOINT BulkOutEndpoint;
- DEBUG_USB_ENDPOINT BulkInEndpoint;
- DEBUG_USB_TRANSFER TransferOut;
- DEBUG_USB_TRANSFER TransferIn;
- ULONG TransferInOffset;
- BOOL TransferInQueued;
- BOOL TransferInSetup;
- USHORT Index;
- FTDI_CHIP_TYPE ChipType;
- } KD_FTDI_DEVICE, *PKD_FTDI_DEVICE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- KdpFtdiReset (
- PVOID Context,
- ULONG BaudRate
- );
- KSTATUS
- KdpFtdiTransmit (
- PVOID Context,
- PVOID Data,
- ULONG Size
- );
- KSTATUS
- KdpFtdiReceive (
- PVOID Context,
- PVOID Data,
- PULONG Size
- );
- KSTATUS
- KdpFtdiGetStatus (
- PVOID Context,
- PBOOL ReceiveDataAvailable
- );
- VOID
- KdpFtdiDisconnect (
- PVOID Context
- );
- KSTATUS
- KdpFtdiInitializeEndpoints (
- PKD_FTDI_DEVICE Device
- );
- ULONG
- KdpFtdiCalculateDivisor (
- PKD_FTDI_DEVICE Device,
- ULONG BaudRate,
- PUSHORT Value,
- PUSHORT Index
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- CHAR KdFtdiAmAdjustUp[8] = {0, 0, 0, 1, 0, 3, 2, 1};
- CHAR KdFtdiAmAdjustDown[8] = {0, 0, 0, 1, 0, 1, 2, 3};
- CHAR KdFtdiFractionCode[8] = {0, 3, 2, 4, 1, 5, 6, 7};
- DEBUG_DEVICE_DESCRIPTION KdFtdiInterfaceTemplate = {
- DEBUG_DEVICE_DESCRIPTION_VERSION,
- {
- KdpFtdiReset,
- KdpFtdiTransmit,
- KdpFtdiReceive,
- KdpFtdiGetStatus,
- KdpFtdiDisconnect
- },
- NULL
- };
- //
- // Store the single device instance.
- //
- KD_FTDI_DEVICE KdFtdiDevice;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- KdpFtdiDriverEntry (
- PKD_USB_DEVICE Device,
- PDEBUG_DEVICE_DESCRIPTION Interface
- )
- /*++
- Routine Description:
- This routine initializes an FTDI USB to Serial KD USB device.
- Arguments:
- Device - Supplies a pointer to the device the driver lives on.
- Interface - Supplies a pointer where the driver fills in the I/O
- interface on success.
- Return Value:
- Status code.
- --*/
- {
- PKD_FTDI_DEVICE FtdiDevice;
- KSTATUS Status;
- //
- // Use a single static device.
- //
- FtdiDevice = &KdFtdiDevice;
- RtlZeroMemory(FtdiDevice, sizeof(KD_FTDI_DEVICE));
- FtdiDevice->Device = Device;
- Status = KdpFtdiInitializeEndpoints(FtdiDevice);
- if (!KSUCCESS(Status)) {
- goto FtdiDriverEntry;
- }
- RtlCopyMemory(Interface,
- &KdFtdiInterfaceTemplate,
- sizeof(DEBUG_DEVICE_DESCRIPTION));
- Interface->Context = FtdiDevice;
- FtdiDriverEntry:
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- KdpFtdiReset (
- PVOID Context,
- ULONG BaudRate
- )
- /*++
- Routine Description:
- This routine initializes and resets a debug device, preparing it to send
- and receive data.
- Arguments:
- Context - Supplies the pointer to the port's context, provided by the
- hardware module upon initialization.
- BaudRate - Supplies the baud rate to set.
- Return Value:
- STATUS_SUCCESS on success.
- Other status codes on failure. The device will not be used if a failure
- status code is returned.
- --*/
- {
- PKD_FTDI_DEVICE Device;
- ULONG Length;
- USB_SETUP_PACKET Setup;
- KSTATUS Status;
- Device = Context;
- if ((Device->TransferInQueued != FALSE) ||
- (Device->TransferInSetup != FALSE)) {
- Status = KdpUsbRetireTransfer(Device->Device->Controller,
- &(Device->TransferIn));
- if (!KSUCCESS(Status)) {
- goto FtdiResetEnd;
- }
- Device->TransferInQueued = FALSE;
- Device->TransferInSetup = FALSE;
- }
- //
- // Always skip the two status bytes at the beginning of each read.
- //
- Device->TransferInOffset = FTDI_READ_STATUS_SIZE;
- //
- // Reset the device.
- //
- Setup.RequestType = USB_SETUP_REQUEST_TO_DEVICE |
- USB_SETUP_REQUEST_VENDOR |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- Setup.Request = FTDI_REQUEST_RESET;
- Setup.Value = 0;
- Setup.Index = Device->Index;
- Setup.Length = 0;
- Length = Setup.Length;
- Status = KdpUsbDefaultControlTransfer(Device->Device,
- &Setup,
- DebugUsbTransferDirectionOut,
- NULL,
- &Length);
- if (!KSUCCESS(Status)) {
- goto FtdiResetEnd;
- }
- //
- // Set the baud rate.
- //
- Setup.Request = FTDI_REQUEST_SET_BAUD_RATE;
- KdpFtdiCalculateDivisor(Device, BaudRate, &(Setup.Value), &(Setup.Index));
- Status = KdpUsbDefaultControlTransfer(Device->Device,
- &Setup,
- DebugUsbTransferDirectionOut,
- NULL,
- &Length);
- if (!KSUCCESS(Status)) {
- goto FtdiResetEnd;
- }
- //
- // Initialize the outbound and inbound transfers.
- //
- RtlZeroMemory(&(Device->TransferOut), sizeof(DEBUG_USB_TRANSFER));
- Device->TransferOut.Endpoint = &(Device->BulkOutEndpoint);
- Device->TransferOut.Direction = DebugUsbTransferDirectionOut;
- Device->TransferOut.Length = 0;
- RtlZeroMemory(&(Device->TransferIn), sizeof(DEBUG_USB_TRANSFER));
- Device->TransferIn.Endpoint = &(Device->BulkInEndpoint);
- Device->TransferIn.Direction = DebugUsbTransferDirectionIn;
- Device->TransferIn.Length = 0;
- //
- // Reset the endpoints.
- //
- Device->BulkInEndpoint.DataToggle = FALSE;
- Device->BulkOutEndpoint.DataToggle = FALSE;
- FtdiResetEnd:
- return Status;
- }
- KSTATUS
- KdpFtdiTransmit (
- PVOID Context,
- PVOID Data,
- ULONG Size
- )
- /*++
- Routine Description:
- This routine transmits data from the host out through the debug device.
- Arguments:
- Context - Supplies the pointer to the port's context, provided by the
- hardware module upon initialization.
- Data - Supplies a pointer to the data to write.
- Size - Supplies the size to write, in bytes.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- ULONG BytesThisRound;
- PKD_FTDI_DEVICE Device;
- KSTATUS Status;
- Device = Context;
- while (Size != 0) {
- BytesThisRound = Device->BulkOutEndpoint.MaxPacketSize;
- if (BytesThisRound > Size) {
- BytesThisRound = Size;
- }
- Device->TransferOut.Length = BytesThisRound;
- Status = KdpUsbSetupTransfer(Device->Device->Controller,
- &(Device->TransferOut));
- if (!KSUCCESS(Status)) {
- goto FtdiTransmitEnd;
- }
- RtlCopyMemory(Device->TransferOut.Buffer, Data, BytesThisRound);
- Status = KdpUsbSubmitTransfer(Device->Device->Controller,
- &(Device->TransferOut),
- TRUE);
- KdpUsbRetireTransfer(Device->Device->Controller,
- &(Device->TransferOut));
- if (!KSUCCESS(Status)) {
- goto FtdiTransmitEnd;
- }
- Data += BytesThisRound;
- Size -= BytesThisRound;
- }
- Status = STATUS_SUCCESS;
- FtdiTransmitEnd:
- return Status;
- }
- KSTATUS
- KdpFtdiReceive (
- PVOID Context,
- PVOID Data,
- PULONG Size
- )
- /*++
- Routine Description:
- This routine receives incoming data from the debug device.
- Arguments:
- Context - Supplies the pointer to the port's context, provided by the
- hardware module upon initialization.
- Data - Supplies a pointer where the read data will be returned on success.
- Size - Supplies a pointer that on input contains the size of the receive
- buffer. On output, returns the number of bytes read.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_NO_DATA_AVAILABLE if there was no data to be read at the current
- time.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- ULONG BytesThisRound;
- ULONG BytesToRead;
- PHARDWARE_USB_DEBUG_DEVICE Controller;
- PKD_FTDI_DEVICE Device;
- KSTATUS Status;
- PDEBUG_USB_TRANSFER TransferIn;
- Device = Context;
- Controller = Device->Device->Controller;
- TransferIn = &(Device->TransferIn);
- BytesToRead = *Size;
- Status = STATUS_SUCCESS;
- while (BytesToRead != 0) {
- //
- // If the transfer is currently queued, check to see if it's finished.
- //
- if (Device->TransferInQueued != FALSE) {
- Status = KdpUsbCheckTransfer(Controller, TransferIn);
- if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
- if (BytesToRead != *Size) {
- Status = STATUS_SUCCESS;
- } else {
- Status = STATUS_NO_DATA_AVAILABLE;
- }
- break;
- //
- // If checking the transfer failed, retire it and stop.
- //
- } else if (!KSUCCESS(Status)) {
- KdpUsbRetireTransfer(Controller, TransferIn);
- Device->TransferIn.LengthTransferred = 0;
- Device->TransferInQueued = FALSE;
- Device->TransferInSetup = FALSE;
- break;
- }
- //
- // The transfer is complete. Set the offset to skip the two status
- // bytes.
- //
- Device->TransferInQueued = FALSE;
- Device->TransferInOffset = FTDI_READ_STATUS_SIZE;
- }
- //
- // Copy bytes from the completed transfer.
- //
- if (Device->TransferInOffset < TransferIn->LengthTransferred) {
- BytesThisRound = TransferIn->LengthTransferred -
- Device->TransferInOffset;
- if (BytesThisRound > BytesToRead) {
- BytesThisRound = BytesToRead;
- }
- RtlCopyMemory(Data,
- TransferIn->Buffer + Device->TransferInOffset,
- BytesThisRound);
- Device->TransferInOffset += BytesThisRound;
- BytesToRead -= BytesThisRound;
- Data += BytesThisRound;
- }
- //
- // If the transfer was completely consumed by the caller, resubmit the
- // transfer.
- //
- if (Device->TransferInOffset >= TransferIn->LengthTransferred) {
- //
- // Retire the transfer if it hasn't been done yet.
- //
- if (Device->TransferInSetup != FALSE) {
- KdpUsbRetireTransfer(Controller, TransferIn);
- Device->TransferInSetup = FALSE;
- }
- //
- // Set up the transfer.
- //
- Device->TransferIn.Length = Device->BulkInEndpoint.MaxPacketSize;
- Status = KdpUsbSetupTransfer(Controller, TransferIn);
- if (!KSUCCESS(Status)) {
- break;
- }
- Device->TransferInSetup = TRUE;
- //
- // Submit the transfer asynchronously.
- //
- Status = KdpUsbSubmitTransfer(Controller, TransferIn, FALSE);
- if (!KSUCCESS(Status)) {
- KdpUsbRetireTransfer(Controller, TransferIn);
- Device->TransferInSetup = FALSE;
- break;
- }
- Device->TransferInQueued = TRUE;
- }
- }
- //
- // Return the number of bytes transferred.
- //
- *Size = *Size - BytesToRead;
- return Status;
- }
- KSTATUS
- KdpFtdiGetStatus (
- PVOID Context,
- PBOOL ReceiveDataAvailable
- )
- /*++
- Routine Description:
- This routine returns the current device status.
- Arguments:
- Context - Supplies the pointer to the port's context, provided by the
- hardware module upon initialization.
- ReceiveDataAvailable - Supplies a pointer where a boolean will be returned
- indicating whether or not receive data is available.
- Return Value:
- Status code.
- --*/
- {
- PHARDWARE_USB_DEBUG_DEVICE Controller;
- PKD_FTDI_DEVICE Device;
- KSTATUS Status;
- PDEBUG_USB_TRANSFER TransferIn;
- *ReceiveDataAvailable = FALSE;
- Device = Context;
- Controller = Device->Device->Controller;
- TransferIn = &(Device->TransferIn);
- //
- // If there is still data to read from a previous transfer, return that
- // there is data available.
- //
- if ((Device->TransferInSetup != FALSE) &&
- (Device->TransferInQueued == FALSE)) {
- if (Device->TransferInOffset < TransferIn->LengthTransferred) {
- *ReceiveDataAvailable = TRUE;
- Status = STATUS_SUCCESS;
- goto FtdiGetStatusEnd;
- //
- // This situation shouldn't hit, as it implies that the receive loop
- // ran out of data but didn't retire the transfer. Handle it anyway.
- //
- } else {
- KdpUsbRetireTransfer(Controller, TransferIn);
- Device->TransferInSetup = FALSE;
- }
- }
- //
- // Set up the transfer if it is not yet created.
- //
- if (Device->TransferInSetup == FALSE) {
- Device->TransferIn.Length = Device->BulkInEndpoint.MaxPacketSize;
- Status = KdpUsbSetupTransfer(Controller, TransferIn);
- if (!KSUCCESS(Status)) {
- goto FtdiGetStatusEnd;
- }
- Device->TransferInSetup = TRUE;
- }
- //
- // Submit the transfer (asynchronously) if it is not already queued.
- //
- if (Device->TransferInQueued == FALSE) {
- Status = KdpUsbSubmitTransfer(Controller, TransferIn, FALSE);
- if (!KSUCCESS(Status)) {
- KdpUsbRetireTransfer(Controller, TransferIn);
- Device->TransferInSetup = FALSE;
- goto FtdiGetStatusEnd;
- }
- Device->TransferInQueued = TRUE;
- }
- //
- // Check the transfer to see if it's finished.
- //
- Status = KdpUsbCheckTransfer(Controller, TransferIn);
- if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
- Status = STATUS_SUCCESS;
- } else if ((!KSUCCESS(Status)) ||
- (TransferIn->LengthTransferred <= FTDI_READ_STATUS_SIZE)) {
- KdpUsbRetireTransfer(Controller, TransferIn);
- Device->TransferInQueued = FALSE;
- Device->TransferInSetup = FALSE;
- //
- // If there was data other than the status bytes, return it.
- //
- } else {
- Device->TransferInQueued = FALSE;
- Device->TransferInOffset = FTDI_READ_STATUS_SIZE;
- *ReceiveDataAvailable = TRUE;
- }
- FtdiGetStatusEnd:
- return Status;
- }
- VOID
- KdpFtdiDisconnect (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine disconnects a device, taking it offline.
- Arguments:
- Context - Supplies the pointer to the port's context, provided by the
- hardware module upon initialization.
- Return Value:
- None.
- --*/
- {
- PKD_FTDI_DEVICE Device;
- Device = Context;
- //
- // Cancel the IN transfer.
- //
- if (Device->TransferInSetup != FALSE) {
- KdpUsbRetireTransfer(Device->Device->Controller, &(Device->TransferIn));
- Device->TransferInQueued = FALSE;
- Device->TransferInSetup = FALSE;
- }
- return;
- }
- KSTATUS
- KdpFtdiInitializeEndpoints (
- PKD_FTDI_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reads the configuration descriptor and initializes the FTDI
- endpoint information.
- Arguments:
- Device - Supplies a pointer to the FTDI device.
- Return Value:
- Status code.
- --*/
- {
- UCHAR Buffer[KD_FTDI_CONFIGURATION_BUFFER_SIZE];
- PUSB_CONFIGURATION_DESCRIPTOR Configuration;
- PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
- PUSB_ENDPOINT_DESCRIPTOR Endpoint;
- ULONG EndpointCount;
- ULONG EndpointIndex;
- BOOL FoundIn;
- BOOL FoundOut;
- PUSB_INTERFACE_DESCRIPTOR Interface;
- ULONG Length;
- USB_SETUP_PACKET Setup;
- KSTATUS Status;
- Device->ChipType = FtdiTypeBm;
- //
- // Request the default configuration.
- //
- RtlZeroMemory(&Setup, sizeof(USB_SETUP_PACKET));
- Setup.RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- Setup.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
- Setup.Value = (UsbDescriptorTypeConfiguration << 8) | 0;
- Setup.Index = 0;
- Setup.Length = sizeof(Buffer);
- Length = Setup.Length;
- Configuration = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer;
- Status = KdpUsbDefaultControlTransfer(Device->Device,
- &Setup,
- DebugUsbTransferDirectionIn,
- Configuration,
- &Length);
- if (!KSUCCESS(Status)) {
- goto FtdiInitializeEndpointsEnd;
- }
- if (Length < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto FtdiInitializeEndpointsEnd;
- }
- //
- // Loop through the interfaces looking for a hub interface.
- //
- FoundIn = FALSE;
- FoundOut = FALSE;
- Interface = (PUSB_INTERFACE_DESCRIPTOR)((PVOID)Configuration +
- Configuration->Length);
- if (Configuration->InterfaceCount == 2) {
- Device->ChipType = FtdiType2232C;
- if (Device->Index == FTDI_INTERFACE_ANY) {
- Device->Index = FTDI_INTERFACE_A;
- }
- }
- while ((UINTN)(Interface + 1) <= (UINTN)Buffer + Length) {
- Endpoint = ((PVOID)Interface) + Interface->Length;
- if (Interface->DescriptorType == UsbDescriptorTypeInterface) {
- FoundIn = FALSE;
- FoundOut = FALSE;
- //
- // Loop through all the endpoints in the interface.
- //
- EndpointIndex = 0;
- EndpointCount = Interface->EndpointCount;
- while (((UINTN)(Endpoint + 1) <= ((UINTN)Buffer + Length)) &&
- (EndpointIndex < EndpointCount)) {
- if (Endpoint->DescriptorType == UsbDescriptorTypeEndpoint) {
- if ((Endpoint->Attributes &
- USB_ENDPOINT_ATTRIBUTES_TYPE_MASK) ==
- USB_ENDPOINT_ATTRIBUTES_TYPE_BULK) {
- if ((Endpoint->EndpointAddress &
- USB_ENDPOINT_ADDRESS_DIRECTION_IN) != 0) {
- Status = KdpUsbInitializeEndpoint(
- Device->Device,
- Endpoint,
- &(Device->BulkInEndpoint));
- if (KSUCCESS(Status)) {
- FoundIn = TRUE;
- }
- } else {
- Status = KdpUsbInitializeEndpoint(
- Device->Device,
- Endpoint,
- &(Device->BulkOutEndpoint));
- if (KSUCCESS(Status)) {
- FoundOut = TRUE;
- }
- }
- }
- EndpointIndex += 1;
- }
- Endpoint = ((PVOID)Endpoint) + Endpoint->Length;
- }
- if ((FoundIn != FALSE) && (FoundOut != FALSE)) {
- break;
- }
- }
- Interface = (PVOID)Endpoint;
- }
- if ((FoundIn == FALSE) || (FoundOut == FALSE)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto FtdiInitializeEndpointsEnd;
- }
- //
- // Request the device descriptor to get the version out of it.
- //
- Setup.RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- Setup.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
- Setup.Value = UsbDescriptorTypeDevice << 8;
- Setup.Index = 0;
- Setup.Length = sizeof(USB_DEVICE_DESCRIPTOR);
- Length = Setup.Length;
- DeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)Buffer;
- Status = KdpUsbDefaultControlTransfer(Device->Device,
- &Setup,
- DebugUsbTransferDirectionIn,
- DeviceDescriptor,
- &Length);
- if (!KSUCCESS(Status)) {
- goto FtdiInitializeEndpointsEnd;
- }
- if (Length != Setup.Length) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto FtdiInitializeEndpointsEnd;
- }
- if (DeviceDescriptor->DescriptorType != UsbDescriptorTypeDevice) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto FtdiInitializeEndpointsEnd;
- }
- if (DeviceDescriptor->DeviceRevision < FTDI_REVISION_AM) {
- Device->ChipType = FtdiTypeOld;
- } else if ((DeviceDescriptor->DeviceRevision < FTDI_REVISION_BM) &&
- (DeviceDescriptor->SerialNumberStringIndex != 0)) {
- Device->ChipType = FtdiTypeAm;
- } else if (DeviceDescriptor->DeviceRevision < FTDI_REVISION_2232C) {
- Device->ChipType = FtdiTypeBm;
- }
- Status = STATUS_SUCCESS;
- FtdiInitializeEndpointsEnd:
- return Status;
- }
- ULONG
- KdpFtdiCalculateDivisor (
- PKD_FTDI_DEVICE Device,
- ULONG BaudRate,
- PUSHORT Value,
- PUSHORT Index
- )
- /*++
- Routine Description:
- This routine computes the divisor (in the form of index and value fields of
- a setup packet) for a given baud rate.
- Arguments:
- Device - Supplies a pointer to the FTDI device.
- BaudRate - Supplies the desired baud rate.
- Value - Supplies a pointer where the value field will be returned on
- success.
- Index - Supplies a pointer where th index field will be returned on success.
- Return Value:
- Returns the actual baud rate.
- --*/
- {
- ULONG BaudRateDifference;
- ULONG BaudRateEstimate;
- ULONG BestBaudRate;
- ULONG BestBaudRateDifference;
- ULONG BestDivisor;
- ULONG Divisor;
- ULONG EncodedDivisor;
- ULONG Try;
- ULONG TryDivisor;
- if (BaudRate == 0) {
- return 0;
- }
- Divisor = FTDI_FUNDAMENTAL_CLOCK / BaudRate;
- //
- // On AM devices, round down to one of the supported fractional values.
- //
- if (Device->ChipType == FtdiTypeAm) {
- Divisor -= KdFtdiAmAdjustDown[Divisor & 0x7];
- }
- //
- // Try this divisor and the one above it to see which one is closer.
- //
- BestBaudRate = 0;
- BestBaudRateDifference = -1;
- BestDivisor = Divisor;
- for (Try = 0; Try < 2; Try += 1) {
- TryDivisor = Divisor + Try;
- //
- // Round up to the minimum divisor value. BM doesn't support 9
- // through 11, AM doesn't support 9 through 15.
- //
- if (TryDivisor <= 8) {
- TryDivisor = 8;
- } else if ((Device->ChipType > FtdiTypeAm) && (TryDivisor < 12)) {
- TryDivisor = 12;
- } else if (Divisor < 16) {
- TryDivisor = 16;
- } else {
- //
- // For AM devices, round up to the nearest supported fraction. Also
- // make sure the divisor doesn't exceed the maximum.
- //
- if (Device->ChipType <= FtdiTypeAm) {
- TryDivisor = KdFtdiAmAdjustUp[TryDivisor & 7];
- if (TryDivisor > FTDI_MAX_DIVISOR_AM) {
- TryDivisor = FTDI_MAX_DIVISOR_AM;
- }
- } else {
- if (TryDivisor > FTDI_MAX_DIVISOR_BM) {
- TryDivisor = FTDI_MAX_DIVISOR_BM;
- }
- }
- }
- //
- // Go back from the divisor to the baud rate to see how bad the error
- // is.
- //
- BaudRateEstimate = (FTDI_FUNDAMENTAL_CLOCK + (TryDivisor / 2)) /
- TryDivisor;
- if (BaudRateEstimate < BaudRate) {
- BaudRateDifference = BaudRate - BaudRateEstimate;
- } else {
- BaudRateDifference = BaudRateEstimate - BaudRate;
- }
- if ((Try == 0) || (BaudRateDifference < BestBaudRateDifference)) {
- BestDivisor = TryDivisor;
- BestBaudRate = BaudRateEstimate;
- BestBaudRateDifference = BaudRateDifference;
- if (BaudRateDifference == 0) {
- break;
- }
- }
- }
- //
- // Encode the winning divisor.
- //
- EncodedDivisor = (BestDivisor >> 3) |
- (KdFtdiFractionCode[BestDivisor & 0x7] << 14);
- //
- // Handle some special cases outlined in the FTDI spec. An encoded divisor
- // of 0 is 3000000 baud, and 1 is 2000000 baud.
- //
- if (EncodedDivisor == 1) {
- EncodedDivisor = 0;
- } else if (EncodedDivisor == 0x4001) {
- EncodedDivisor = 1;
- }
- //
- // Split the encoded divisor into index and value fields.
- //
- *Value = (USHORT)(EncodedDivisor & 0xFFFF);
- if (Device->ChipType == FtdiType2232C) {
- *Index = ((USHORT)(EncodedDivisor >> 8) & 0xFF00) | Device->Index;
- } else {
- *Index = (USHORT)(EncodedDivisor >> 16);
- }
- return BestBaudRate;
- }
|