root/src/add-ons/kernel/busses/usb/ehci.h
/*
 * Copyright 2006, Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Michael Lotz <mmlr@mlotz.ch>
 */
#ifndef EHCI_H
#define EHCI_H

#include "usb_private.h"
#include "ehci_hardware.h"


struct pci_info;
struct pci_device_module_info;
struct pci_device;

class EHCIRootHub;


typedef struct transfer_data {
        Transfer *              transfer;
        ehci_qh *               queue_head;
        ehci_qtd *              data_descriptor;
        bool                    incoming;
        bool                    canceled;
        transfer_data * link;
} transfer_data;


// This structure is used to create a list of
// descriptors per isochronous transfer
typedef struct isochronous_transfer_data {
        Transfer *                                      transfer;
        // The next field is used to keep track
        // of every isochronous descriptor as they are NOT
        // linked to each other in a queue like in every other
        // transfer type
        ehci_itd **                                     descriptors;
        uint16                                          last_to_process;
        bool                                            incoming;
        bool                                            is_active;
        isochronous_transfer_data *     link;

        size_t                                          buffer_size;
        void *                                          buffer_log;
        addr_t                                          buffer_phy;
} isochronous_transfer_data;


class EHCI : public BusManager {
public:
                                                                        EHCI(pci_info *info, pci_device_module_info* pci,
                                                                                pci_device* device, Stack *stack, device_node *node);
                                                                        ~EHCI();

                status_t                                        Start();

virtual status_t                                        StartDebugTransfer(Transfer *transfer);
virtual status_t                                        CheckDebugTransfer(Transfer *transfer);
                void                                            LinkAsyncDebugQueueHead(ehci_qh *queueHead);
                void                                            LinkPeriodicDebugQueueHead(
                                                                                ehci_qh *queueHead, Pipe *pipe);
virtual void                                            CancelDebugTransfer(Transfer *transfer);
                void                                            CleanupDebugTransfer(Transfer *transfer);

virtual status_t                                        SubmitTransfer(Transfer *transfer);
                status_t                                        SubmitIsochronous(Transfer *transfer);

virtual status_t                                        CancelQueuedTransfers(Pipe *pipe, bool force);
                status_t                                        CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);

virtual status_t                                        NotifyPipeChange(Pipe *pipe,
                                                                                usb_change change);

                // Port operations for root hub
                uint8                                           PortCount() { return fPortCount; }
                status_t                                        GetPortStatus(uint8 index, usb_port_status *status);
                status_t                                        SetPortFeature(uint8 index, uint16 feature);
                status_t                                        ClearPortFeature(uint8 index, uint16 feature);

                status_t                                        ResetPort(uint8 index);
                status_t                                        SuspendPort(uint8 index);

virtual const char *                            TypeName() const { return "ehci"; }

private:
                // Controller resets
                status_t                                        ControllerReset();
                status_t                                        LightReset();

                // Interrupt functions
static  int32                                           InterruptHandler(void *data);
                int32                                           Interrupt();
static  int32                                           InterruptPollThread(void *data);

                // Transfer management
                status_t                                        AddPendingTransfer(Transfer *transfer,
                                                                                ehci_qh *queueHead,
                                                                                ehci_qtd *dataDescriptor,
                                                                                bool directionIn);
                status_t                                        AddPendingIsochronousTransfer(
                                                                                Transfer *transfer,
                                                                                ehci_itd **isoRequest, uint32 lastIndex,
                                                                                bool directionIn, addr_t bufferPhy,
                                                                                void *bufferLog, size_t bufferSize);
                status_t                                        CancelAllPendingTransfers();


static  int32                                           FinishThread(void *data);
                void                                            FinishTransfers();
static  int32                                           CleanupThread(void *data);
                void                                            Cleanup();

                // Isochronous transfer functions
static int32                                            FinishIsochronousThread(void *data);
                void                                            FinishIsochronousTransfers();
                isochronous_transfer_data *     FindIsochronousTransfer(ehci_itd *itd);
                void                                            LinkITDescriptors(ehci_itd *itd,
                                                                                ehci_itd **last);
                void                                            LinkSITDescriptors(ehci_sitd *sitd,
                                                                                ehci_sitd **last);
                void                                            UnlinkITDescriptors(ehci_itd *itd,
                                                                                ehci_itd **last);
                void                                            UnlinkSITDescriptors(ehci_sitd *sitd,
                                                                                ehci_sitd **last);

                // Queue Head functions
                ehci_qh *                                       CreateQueueHead();
                status_t                                        InitQueueHead(ehci_qh *queueHead,
                                                                                Pipe *pipe);
                void                                            FreeQueueHead(ehci_qh *queueHead);

                status_t                                        LinkQueueHead(ehci_qh *queueHead);
                status_t                                        LinkInterruptQueueHead(ehci_qh *queueHead,
                                                                                Pipe *pipe);
                status_t                                        UnlinkQueueHead(ehci_qh *queueHead,
                                                                                ehci_qh **freeList);

                // Queue functions
                status_t                                        FillQueueWithRequest(Transfer *transfer,
                                                                                ehci_qh *queueHead,
                                                                                ehci_qtd **dataDescriptor,
                                                                                bool *directionIn,
                                                                                bool prepareKernelAccess);
                status_t                                        FillQueueWithData(Transfer *transfer,
                                                                                ehci_qh *queueHead,
                                                                                ehci_qtd **dataDescriptor,
                                                                                bool *directionIn,
                                                                                bool prepareKernelAccess);
                status_t                                        _FillQueueWithPhysicalData(Transfer *transfer,
                                                                                ehci_qh *queueHead,
                                                                                ehci_qtd **dataDescriptor,
                                                                                bool *directionIn);

                bool                                            LockIsochronous();
                void                                            UnlockIsochronous();

                // Descriptor functions
                ehci_qtd *                                      CreateDescriptor(
                                                                                size_t bufferSizeToAllocate,
                                                                                uint8 pid);
                status_t                                        CreateDescriptorChain(Pipe *pipe,
                                                                                ehci_qtd **firstDescriptor,
                                                                                ehci_qtd **lastDescriptor,
                                                                                ehci_qtd *strayDescriptor,
                                                                                uint8 pid,
                                                                                size_t buffersLength,
                                                                                int32 descriptorsCount = -1);
                ehci_itd*                                       CreateItdDescriptor();
                ehci_sitd*                                      CreateSitdDescriptor();

                void                                            FreeDescriptor(ehci_qtd *descriptor);
                void                                            FreeDescriptorChain(ehci_qtd *topDescriptor);
                void                                            FreeDescriptor(ehci_itd *descriptor);
                void                                            FreeDescriptor(ehci_sitd *descriptor);
                void                                            FreeIsochronousData(
                                                                                isochronous_transfer_data *data);

                void                                            LinkDescriptors(ehci_qtd *first,
                                                                                ehci_qtd *last, ehci_qtd *alt);

                size_t                                          WriteDescriptorChain(
                                                                                ehci_qtd *topDescriptor,
                                                                                generic_io_vec *vector, size_t vectorCount,
                                                                                bool physical);
                size_t                                          ReadDescriptorChain(ehci_qtd *topDescriptor,
                                                                                generic_io_vec *vector, size_t vectorCount,
                                                                                bool physical, bool *nextDataToggle);
                size_t                                          ReadActualLength(ehci_qtd *topDescriptor,
                                                                                bool *nextDataToggle);
                size_t                                          WriteIsochronousDescriptorChain(
                                                                                isochronous_transfer_data *transfer);
                size_t                                          ReadIsochronousDescriptorChain(
                                                                                isochronous_transfer_data *transfer);

                // Operational register functions
inline  void                                            WriteOpReg(uint32 reg, uint32 value);
inline  uint32                                          ReadOpReg(uint32 reg);

                // Capability register functions
inline  uint8                                           ReadCapReg8(uint32 reg);
inline  uint16                                          ReadCapReg16(uint32 reg);
inline  uint32                                          ReadCapReg32(uint32 reg);

                uint8 *                                         fCapabilityRegisters;
                uint8 *                                         fOperationalRegisters;
                area_id                                         fRegisterArea;
                pci_info *                                      fPCIInfo;
                pci_device_module_info*         fPci;
                pci_device*                                     fDevice;
                Stack *                                         fStack;
                uint32                                          fEnabledInterrupts;
                uint32                                          fThreshold;

                // Periodic transfer framelist and interrupt entries
                area_id                                         fPeriodicFrameListArea;
                uint32 *                                        fPeriodicFrameList;
                interrupt_entry *                       fInterruptEntries;
                ehci_itd **                                     fItdEntries;
                ehci_sitd **                            fSitdEntries;

                // Async transfer queue management
                ehci_qh *                                       fAsyncQueueHead;
                sem_id                                          fAsyncAdvanceSem;

                // Maintain a linked list of transfers
                transfer_data *                         fFirstTransfer;
                transfer_data *                         fLastTransfer;
                sem_id                                          fFinishTransfersSem;
                thread_id                                       fFinishThread;
                Pipe *                                          fProcessingPipe;

                ehci_qh *                                       fFreeListHead;
                sem_id                                          fCleanupSem;
                thread_id                                       fCleanupThread;
                bool                                            fStopThreads;
                int32                                           fNextStartingFrame;

                // fFrameBandwidth[n] holds the available bandwidth
                // of the nth frame in microseconds
                uint16 *                                        fFrameBandwidth;

                // Maintain a linked list of isochronous transfers
                isochronous_transfer_data *     fFirstIsochronousTransfer;
                isochronous_transfer_data *     fLastIsochronousTransfer;
                sem_id                                          fFinishIsochronousTransfersSem;
                thread_id                                       fFinishIsochronousThread;
                mutex                                           fIsochronousLock;

                // Root Hub
                EHCIRootHub *                           fRootHub;
                uint8                                           fRootHubAddress;

                // Port management
                uint8                                           fPortCount;
                uint16                                          fPortResetChange;
                uint16                                          fPortSuspendChange;

                // Interrupt polling
                thread_id                                       fInterruptPollThread;
                uint32                                          fIRQ;
                bool                                            fUseMSI;
};


class EHCIRootHub : public Hub {
public:
                                                                        EHCIRootHub(Object *rootObject,
                                                                                int8 deviceAddress);

static  status_t                                        ProcessTransfer(EHCI *ehci,
                                                                                Transfer *transfer);
};


#endif // !EHCI_H